You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2021/08/13 02:59:20 UTC
[incubator-doris] branch doris-manager updated: [Feature] Doris
manager module (#6424)
This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch doris-manager
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/doris-manager by this push:
new 9f4293e [Feature] Doris manager module (#6424)
9f4293e is described below
commit 9f4293e0b203004399e66318ca2a5297c9588aeb
Author: weajun <we...@gmail.com>
AuthorDate: Fri Aug 13 10:59:05 2021 +0800
[Feature] Doris manager module (#6424)
Server and agent framework.
Doris Manager is a platform product that integrates one-click automatic installation, deployment, management,
monitoring, and tuning of doris clusters. Its service is independent of Doris and aims to provide convenient user
functions through a graphical interface. Manager is compatible with multi-cluster mode, and its functions are divided
into general functions and single-cluster functions as a whole.
---
.gitignore | 11 +
manager/README.md | 52 +++
manager/assembly/package.xml | 40 ++
manager/assembly/pom.xml | 71 +++
manager/dm-agent/pom.xml | 65 +++
.../doris/manager/agent/DmAgentApplication.java | 70 +++
.../doris/manager/agent/api/CommandController.java | 67 +++
.../doris/manager/agent/api/CommonControllder.java | 40 ++
.../doris/manager/agent/command/BeCommand.java | 34 ++
.../manager/agent/command/BeInstallCommand.java | 60 +++
.../manager/agent/command/BeInstallTaskDesc.java | 31 ++
.../manager/agent/command/BeInstallTaskHook.java | 52 +++
.../manager/agent/command/BeStartCommand.java | 49 +++
.../doris/manager/agent/command/BeStopCommand.java | 49 +++
.../doris/manager/agent/command/Command.java | 52 +++
.../manager/agent/command/CommandFactory.java | 63 +++
.../manager/agent/command/CommandListener.java | 23 +
.../doris/manager/agent/command/CommandResult.java | 57 +++
.../agent/command/CommandResultService.java | 98 +++++
.../doris/manager/agent/command/FeCommand.java | 34 ++
.../manager/agent/command/FeInstallCommand.java | 61 +++
.../manager/agent/command/FeInstallTaskDesc.java | 31 ++
.../manager/agent/command/FeInstallTaskHook.java | 53 +++
.../manager/agent/command/FeStartCommand.java | 64 +++
.../doris/manager/agent/command/FeStopCommand.java | 48 ++
.../manager/agent/command/ListenerCommand.java | 27 ++
.../doris/manager/agent/common/AgentConstants.java | 29 ++
.../doris/manager/agent/common/PropertiesUtil.java | 51 +++
.../manager/agent/exception/AgentException.java | 42 ++
.../agent/exception/GlobalExceptionHandler.java | 42 ++
.../doris/manager/agent/register/AgentContext.java | 139 ++++++
.../manager/agent/register/AgentHeartbeat.java | 62 +++
.../manager/agent/register/AgentRegister.java | 44 ++
.../doris/manager/agent/register/AgentRole.java | 40 ++
.../manager/agent/register/ApplicationOption.java | 33 ++
.../doris/manager/agent/register/BaseRequest.java | 66 +++
.../doris/manager/agent/register/BeState.java | 66 +++
.../doris/manager/agent/register/FeState.java | 69 +++
.../doris/manager/agent/register/StateService.java | 39 ++
.../manager/agent/task/AbsAsyncTaskHandler.java | 38 ++
.../manager/agent/task/ITaskHandlerFactory.java | 21 +
.../apache/doris/manager/agent/task/ITaskLog.java | 36 ++
.../org/apache/doris/manager/agent/task/LRU.java | 55 +++
.../manager/agent/task/QueuedTaskHandler.java | 26 ++
.../agent/task/QueuedTaskHandlerFactory.java | 32 ++
.../doris/manager/agent/task/ScriptTask.java | 57 +++
.../doris/manager/agent/task/ScriptTaskDesc.java | 29 ++
.../doris/manager/agent/task/SyncTaskHandler.java | 25 ++
.../manager/agent/task/SyncTaskHandlerFactory.java | 32 ++
.../org/apache/doris/manager/agent/task/Task.java | 84 ++++
.../doris/manager/agent/task/TaskContext.java | 35 ++
.../apache/doris/manager/agent/task/TaskDesc.java | 29 ++
.../manager/agent/task/TaskExecutorService.java | 28 ++
.../doris/manager/agent/task/TaskHandler.java | 29 ++
.../manager/agent/task/TaskHandlerFactory.java | 45 ++
.../apache/doris/manager/agent/task/TaskHook.java | 5 +
.../doris/manager/agent/task/TaskLruLog.java | 92 ++++
.../doris/manager/agent/task/TaskResult.java | 88 ++++
.../apache/doris/manager/agent/task/TaskState.java | 30 ++
.../src/main/resources/agent/bin/agent_start.sh | 88 ++++
.../src/main/resources/agent/bin/agent_stop.sh | 40 ++
.../src/main/resources/agent/bin/install_be.sh | 68 +++
.../src/main/resources/agent/bin/install_fe.sh | 68 +++
.../src/main/resources/application.properties | 1 +
.../dm-agent/src/main/resources/logback-spring.xml | 26 ++
manager/dm-common/pom.xml | 15 +
.../common/domain/BeInstallCommandRequestBody.java | 48 ++
.../manager/common/domain/CommandRequest.java | 38 ++
.../doris/manager/common/domain/CommandType.java | 40 ++
.../common/domain/FeInstallCommandRequestBody.java | 47 ++
.../common/domain/FeStartCommandRequestBody.java | 38 ++
.../doris/manager/common/domain/RResult.java | 84 ++++
.../apache/doris/manager/common/domain/Role.java | 31 ++
manager/dm-server/pom.xml | 83 ++++
.../doris/manager/server/DmServerApplication.java | 28 ++
.../doris/manager/server/agent/AgentCache.java | 68 +++
.../manager/server/agent/AgentHeatbeatRunner.java | 85 ++++
.../doris/manager/server/agent/AgentRest.java | 63 +++
.../manager/server/config/RestTemplateConfig.java | 30 ++
.../manager/server/constants/AgentStatus.java | 22 +
.../manager/server/constants/CmdTypeEnum.java | 32 ++
.../doris/manager/server/constants/Constants.java | 24 +
.../manager/server/controller/AgentController.java | 79 ++++
.../server/controller/ServerController.java | 90 ++++
.../apache/doris/manager/server/dao/ServerDao.java | 44 ++
.../manager/server/dao/impl/ServerDaoImpl.java | 160 +++++++
.../doris/manager/server/entity/AgentEntity.java | 103 +++++
.../manager/server/entity/AgentRoleEntity.java | 59 +++
.../server/exceptions/GlobalExceptionHandler.java | 42 ++
.../manager/server/exceptions/ServerException.java | 42 ++
.../manager/server/model/req/AgentCommon.java | 40 ++
.../doris/manager/server/model/req/DorisExec.java | 50 +++
.../manager/server/model/req/DorisExecReq.java | 43 ++
.../manager/server/model/req/DorisInstallReq.java | 32 ++
.../manager/server/model/req/InstallInfo.java | 82 ++++
.../doris/manager/server/model/req/SshInfo.java | 62 +++
.../manager/server/model/req/TaskInfoReq.java | 40 ++
.../doris/manager/server/model/req/TaskLogReq.java | 29 ++
.../doris/manager/server/service/ServerAgent.java | 54 +++
.../manager/server/service/ServerProcess.java | 53 +++
.../server/service/impl/ServerAgentImpl.java | 180 ++++++++
.../server/service/impl/ServerProcessImpl.java | 204 +++++++++
.../doris/manager/server/shell/BaseCommand.java | 85 ++++
.../org/apache/doris/manager/server/shell/SCP.java | 54 +++
.../org/apache/doris/manager/server/shell/SSH.java | 54 +++
.../doris/manager/server/util/Preconditions.java | 46 ++
.../doris/manager/server/util/PropertiesUtil.java | 51 +++
.../src/main/resources/application.properties | 15 +
.../dm-server/src/main/resources/bin/startup.sh | 60 +++
manager/dm-server/src/main/resources/bin/stop.sh | 39 ++
manager/dm-server/src/main/resources/dm-server.sql | 18 +
.../src/main/resources/logback-spring.xml | 26 ++
...216\245\345\217\243\346\226\207\346\241\243.md" | 486 +++++++++++++++++++++
manager/pom.xml | 48 ++
114 files changed, 6377 insertions(+)
diff --git a/.gitignore b/.gitignore
index e5b8456..5b6b800 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,17 @@ docs/package-lock.json
fe/fe-common/.classpath
rpc_data/
+manager/assembly/target
+manager/assembly/output/*
+manager/assembly/assembly.iml
+manager/dm-agent/target
+manager/dm-agent/dm-agent.iml
+manager/dm-common/target
+manager/dm-common/dm-common.iml
+manager/dm-server/target
+manager/dm-server/dm-server.iml
+manager/.idea/
+manager/manager.iml
#ignore vscode project file
.vscode
diff --git a/manager/README.md b/manager/README.md
new file mode 100644
index 0000000..3a40c9c
--- /dev/null
+++ b/manager/README.md
@@ -0,0 +1,52 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Apache Doris Manager (incubating)
+[![Join the chat at https://gitter.im/apache-doris/Lobby](https://badges.gitter.im/apache-doris/Lobby.svg)](https://gitter.im/apache-doris/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Apache Doris Manager is used to manage the doris cluster, such as installing the cluster, upgrading the cluster, starting and stopping services, etc.
+
+## 1.Database configuration
+
+* Modify the database configuration in the manager/dm-server/src/main/resources/application.properties file.
+* Create a new database, and then execute the table creation statement in the manager/dm-server/src/main/resources/dm-server.sql file
+
+## 2. Compile and install
+
+### Step1: build
+```
+$ mvn clean package -DskipTests
+```
+After compilation, a tar package will be generated in the assembly/output/ directory, For example doris-manager-1.0.0.tar.gz
+
+### Step2: install manager server
+Copy tar package to the the machine where the manager server needs to be installed, Start the manager service after decompression
+```
+$ tar zxf doris-manager-1.0.0.tar.gz
+$ sh bin/startup.sh
+```
+
+### Step3: install agent service
+After decompressing the tar package in the second step, there will be a directory called agent. copy the agent directory to the
+machine where the agent service is installed,
+```
+$ sh bin/agent_start.sh --agent ${agentIp} --server ${serverIp}:9601
+```
+${agentIp} is the IP of the machine where the agent is located, ${serverIp} is the IP of the machine where the manager server is located
+
diff --git a/manager/assembly/package.xml b/manager/assembly/package.xml
new file mode 100644
index 0000000..f948820
--- /dev/null
+++ b/manager/assembly/package.xml
@@ -0,0 +1,40 @@
+<assembly xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/assembly-1.0.0.xsd">
+ <id>package</id>
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>../dm-agent/src/main/resources/agent</directory>
+ <outputDirectory>./agent</outputDirectory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>../dm-server/src/main/resources/bin</directory>
+ <outputDirectory>./bin</outputDirectory>
+ </fileSet>
+ <fileSet>
+ <directory>log</directory>
+ <outputDirectory>./log</outputDirectory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+ <files>
+ <file>
+ <source>../dm-agent/target/dm-agent-${project.parent.version}.jar</source>
+ <outputDirectory>./agent/lib</outputDirectory>
+ <destName>dm-agent.jar</destName>
+ </file>
+ <file>
+ <source>../dm-server/target/dm-server-${project.parent.version}.jar</source>
+ <outputDirectory>./lib</outputDirectory>
+ <destName>dm-server.jar</destName>
+ </file>
+ </files>
+</assembly>
\ No newline at end of file
diff --git a/manager/assembly/pom.xml b/manager/assembly/pom.xml
new file mode 100644
index 0000000..462b891
--- /dev/null
+++ b/manager/assembly/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>doris-manager</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>assembly</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-agent</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-server</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <id>folder</id>
+ <phase>validate</phase>
+ <configuration>
+ <tasks>
+ <echo message="clean output directory"/>
+ <delete dir="./output"/>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <finalName>doris-manager-${project.parent.version}</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>assembly/package.xml</descriptor>
+ </descriptors>
+ <outputDirectory>./output</outputDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/manager/dm-agent/pom.xml b/manager/dm-agent/pom.xml
new file mode 100644
index 0000000..890b71f
--- /dev/null
+++ b/manager/dm-agent/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>doris-manager</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dm-agent</artifactId>
+ <packaging>jar</packaging>
+
+ <name>dm-agent</name>
+
+ <properties>
+ <java.version>1.8</java.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-common</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>1.2.61</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>args4j</groupId>
+ <artifactId>args4j</artifactId>
+ <version>2.33</version>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java
new file mode 100644
index 0000000..791ab1d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/DmAgentApplication.java
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.register.AgentHeartbeat;
+import org.apache.doris.manager.agent.register.AgentRegister;
+import org.apache.doris.manager.agent.register.AgentRole;
+import org.apache.doris.manager.agent.register.ApplicationOption;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.common.PropertiesUtil;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.system.ApplicationHome;
+
+@SpringBootApplication
+public class DmAgentApplication {
+ private static final Logger log = LoggerFactory.getLogger(DmAgentApplication.class);
+
+ public static void main(String[] args) {
+ ApplicationOption option = new ApplicationOption();
+ CmdLineParser parser = new CmdLineParser(option);
+ try {
+ parser.parseArgument(args);
+ } catch (CmdLineException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ String agentPort = PropertiesUtil.getPropValue("server.port");
+
+ ApplicationHome applicationHome = new ApplicationHome(DmAgentApplication.class);
+ String agentInstallDir = applicationHome.getSource().getParentFile().getParentFile().toString();
+
+ AgentContext.init(option.role, option.agentIp, Integer.valueOf(agentPort), option.agentServer, option.dorisHomeDir, agentInstallDir);
+
+
+ String role = AgentRole.queryRole();
+ AgentContext.setRole(Role.findByName(role));
+
+ // register agent
+ boolean register = AgentRegister.register();
+ if (register) {
+ SpringApplication.run(DmAgentApplication.class, args);
+ AgentHeartbeat.start();
+ } else {
+ log.error("agent register fail!");
+ return;
+ }
+ }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java
new file mode 100644
index 0000000..368f95e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommandController.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.api;
+
+import org.apache.doris.manager.agent.command.CommandFactory;
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.agent.command.CommandResult;
+import org.apache.doris.manager.agent.command.CommandResultService;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskContext;
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Objects;
+
+@RestController
+@RequestMapping("/command")
+public class CommandController {
+
+ @PostMapping("/execute")
+ public RResult execute(@RequestBody CommandRequest commandRequest) {
+ if (Objects.isNull(CommandType.findByName(commandRequest.getCommandType()))) {
+ return RResult.error("unkonwn command");
+ }
+ Task task = CommandFactory.get(commandRequest).setup().execute();
+ CommandResult commandResult = new CommandResult(task.getTaskResult(),
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+ return RResult.success(commandResult);
+ }
+
+ @GetMapping("/result")
+ public RResult commandResult(@RequestParam String taskId) {
+ return RResult.success(CommandResultService.commandResult(taskId));
+ }
+
+ @GetMapping("/stdlog")
+ public RResult getTaskStdLog(@RequestParam String taskId, @RequestParam int offset) {
+ return RResult.success(TaskContext.getTaskByTaskId(taskId) == null ? null : TaskContext.getTaskByTaskId(taskId).getTasklog().stdLog(offset, AgentConstants.COMMAND_LOG_PAGE_SIZE));
+ }
+
+ @GetMapping("/errlog")
+ public RResult getTaskErrLog(@RequestParam String taskId, @RequestParam int offset) {
+ return RResult.success(TaskContext.getTaskByTaskId(taskId) == null ? null : TaskContext.getTaskByTaskId(taskId).getTasklog().errLog(offset, AgentConstants.COMMAND_LOG_PAGE_SIZE));
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java
new file mode 100644
index 0000000..da6a843
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/api/CommonControllder.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.api;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.register.StateService;
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/common")
+public class CommonControllder {
+
+ @GetMapping("/state")
+ public RResult state() {
+ return RResult.success(StateService.isHealth());
+ }
+
+ @GetMapping("/context")
+ public RResult context() {
+ return RResult.success(AgentContext.getContext());
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java
new file mode 100644
index 0000000..ee28f5b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeCommand.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public abstract class BeCommand extends ListenerCommand {
+ @Override
+ public void beforeExecute(CommandType commandType) {
+ if (Objects.isNull(AgentContext.getServiceInstallDir()) || Objects.isNull(AgentContext.getRole()) ||
+ AgentContext.getRole() != Role.BE) {
+ throw new AgentException("service be not installed");
+ }
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java
new file mode 100644
index 0000000..2a582dd
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallCommand.java
@@ -0,0 +1,60 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class BeInstallCommand extends Command {
+ private BeInstallCommandRequestBody requestBody;
+
+ public BeInstallCommand(BeInstallCommandRequestBody requestBody) {
+ this.requestBody = requestBody;
+ }
+
+ @Override
+ public Task setupTask() {
+ BeInstallTaskDesc taskDesc = new BeInstallTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getAgentInstallDir() + "/bin/install_be.sh ";
+ scriptCmd += " --installDir " + requestBody.getInstallDir();
+ scriptCmd += " --url " + requestBody.getPackageUrl();
+ if (requestBody.isMkBeStorageDir()) {
+ scriptCmd += " --mkBeStorageDir";
+ }
+ taskDesc.setScriptCmd(scriptCmd);
+ taskDesc.setInstallDir(requestBody.getInstallDir());
+ return new ScriptTask(taskDesc, new BeInstallTaskHook());
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.INSTALL_BE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java
new file mode 100644
index 0000000..c6a1c9a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskDesc.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+
+public class BeInstallTaskDesc extends ScriptTaskDesc {
+ private String installDir;
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java
new file mode 100644
index 0000000..33f874e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeInstallTaskHook.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.task.TaskHook;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+public class BeInstallTaskHook extends TaskHook<BeInstallTaskDesc> {
+ @Override
+ public void onSuccess(BeInstallTaskDesc taskDesc) {
+ AgentContext.setRole(Role.BE);
+ AgentContext.setServiceInstallDir(taskDesc.getInstallDir());
+
+ String configFile = AgentContext.getServiceInstallDir().endsWith("/") ? AgentContext.getServiceInstallDir() + "conf/be.conf" : AgentContext.getServiceInstallDir() + "/conf/be.conf";
+ Properties props = null;
+ try {
+ props = new Properties();
+ props.load(new FileReader(configFile));
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new AgentException("load be conf file fail:" + configFile);
+ }
+
+ if (props != null && Strings.isNotBlank(props.getProperty("http_port"))) {
+ AgentContext.setHealthCheckPort(Integer.valueOf(props.getProperty("http_port")));
+ } else {
+ AgentContext.setHealthCheckPort(AgentConstants.BE_HTTP_PORT_DEFAULT);
+ }
+ }
+}
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java
new file mode 100644
index 0000000..8996cb6
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStartCommand.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class BeStartCommand extends BeCommand {
+ @Override
+ public Task setupTask() {
+ ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getServiceInstallDir() + "/bin/start_be.sh --daemon";
+ taskDesc.setScriptCmd(scriptCmd);
+ return new ScriptTask(taskDesc);
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.START_BE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java
new file mode 100644
index 0000000..baa93e1
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/BeStopCommand.java
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+
+public class BeStopCommand extends BeCommand {
+ @Override
+ public Task setupTask() {
+ ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getServiceInstallDir() + "/bin/stop_be.sh ";
+ taskDesc.setScriptCmd(scriptCmd);
+ return new ScriptTask(taskDesc);
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.STOP_BE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java
new file mode 100644
index 0000000..e89c04a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/Command.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.common.domain.CommandType;
+
+
+public abstract class Command {
+ private Task task;
+ private ITaskHandlerFactory handlerFactory;
+ protected CommandType commandType;
+
+
+ public Command setup() {
+ task = setupTask();
+ commandType = setupCommandType();
+ task.getTaskDesc().setTaskName(commandType.name());
+ handlerFactory = setupTaskHandlerFactory();
+ return this;
+ }
+
+ public abstract Task setupTask();
+
+ public abstract CommandType setupCommandType();
+
+ public abstract ITaskHandlerFactory setupTaskHandlerFactory();
+
+ public Task execute() {
+ handlerFactory.createTaskHandler().handle(task);
+ return task;
+ }
+
+ public ITaskHandlerFactory getHandlerFactory() {
+ return handlerFactory;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java
new file mode 100644
index 0000000..e42bb27
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandFactory.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+public class CommandFactory {
+ public static Command get(CommandRequest commandRequest) {
+ String body = null;
+ if (Strings.isNotBlank(commandRequest.getBody())) {
+ try {
+ body = URLDecoder.decode(commandRequest.getBody(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ throw new AgentException(e.getMessage());
+ }
+ }
+
+ switch (CommandType.valueOf(commandRequest.getCommandType())) {
+ case INSTALL_FE:
+ FeInstallCommandRequestBody feInstallCommandRequestBody = JSON.parseObject(body, FeInstallCommandRequestBody.class);
+ return new FeInstallCommand(feInstallCommandRequestBody);
+ case INSTALL_BE:
+ BeInstallCommandRequestBody beInstallCommandRequestBody = JSON.parseObject(body, BeInstallCommandRequestBody.class);
+ return new BeInstallCommand(beInstallCommandRequestBody);
+ case START_FE:
+ FeStartCommandRequestBody feStartCommandRequestBody = JSON.parseObject(body, FeStartCommandRequestBody.class);
+ return new FeStartCommand(feStartCommandRequestBody);
+ case STOP_FE:
+ return new FeStopCommand();
+ case START_BE:
+ return new BeStartCommand();
+ case STOP_BE:
+ return new BeStopCommand();
+ default:
+ throw new AgentException("unkown CommandType");
+ }
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java
new file mode 100644
index 0000000..9a1dce1
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandListener.java
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.common.domain.CommandType;
+
+public interface CommandListener {
+ void beforeExecute(CommandType commandType);
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java
new file mode 100644
index 0000000..3575b24
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResult.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.TaskResult;
+
+import java.util.List;
+
+public class CommandResult {
+ private TaskResult taskResult;
+ private List<String> stdlogs;
+ private List<String> errlogs;
+
+ public CommandResult(TaskResult taskResult, List<String> stdlogs, List<String> errlogs) {
+ this.taskResult = taskResult;
+ this.stdlogs = stdlogs;
+ this.errlogs = errlogs;
+ }
+
+ public TaskResult getTaskResult() {
+ return taskResult;
+ }
+
+ public void setTaskResult(TaskResult taskResult) {
+ this.taskResult = taskResult;
+ }
+
+ public List<String> getStdlogs() {
+ return stdlogs;
+ }
+
+ public void setStdlogs(List<String> stdlogs) {
+ this.stdlogs = stdlogs;
+ }
+
+ public List<String> getErrlogs() {
+ return errlogs;
+ }
+
+ public void setErrlogs(List<String> errlogs) {
+ this.errlogs = errlogs;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java
new file mode 100644
index 0000000..451df4b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/CommandResultService.java
@@ -0,0 +1,98 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.register.BeState;
+import org.apache.doris.manager.agent.register.FeState;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskContext;
+import org.apache.doris.manager.agent.task.TaskResult;
+import org.apache.doris.manager.common.domain.CommandType;
+
+import java.util.Objects;
+
+public class CommandResultService {
+ public static CommandResult commandResult(String taskId) {
+ if (Objects.isNull(TaskContext.getTaskByTaskId(taskId))) {
+ return null;
+ }
+
+ Task task = TaskContext.getTaskByTaskId(taskId);
+ CommandResult commandResult = new CommandResult(task.getTaskResult(),
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+
+ switch (CommandType.valueOf(task.getTaskDesc().getTaskName())) {
+ case INSTALL_FE:
+ case INSTALL_BE:
+ return commandResult;
+ case START_FE:
+ return feStateResult(task, false);
+ case STOP_FE:
+ return feStateResult(task, true);
+ case START_BE:
+ return beStateResult(task, false);
+ case STOP_BE:
+ return beStateResult(task, true);
+ default:
+ return null;
+ }
+ }
+
+ private static CommandResult feStateResult(Task task, boolean isStop) {
+ if (Objects.isNull(task.getTaskResult().getRetCode()) || task.getTaskResult().getRetCode() != 0) {
+ return new CommandResult(task.getTaskResult(),
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+ }
+
+ // todo: save final status
+ TaskResult tmpTaskResult = new TaskResult(task.getTaskResult());
+ boolean health = FeState.isHealth();
+ if (isStop) {
+ tmpTaskResult.setRetCode(!health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+ } else {
+ tmpTaskResult.setRetCode(health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+ }
+
+ return new CommandResult(tmpTaskResult,
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+ }
+
+ private static CommandResult beStateResult(Task task, boolean isStop) {
+ if (Objects.isNull(task.getTaskResult().getRetCode()) || task.getTaskResult().getRetCode() != 0) {
+ return new CommandResult(task.getTaskResult(),
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+ }
+
+ // todo: save final status
+ TaskResult tmpTaskResult = new TaskResult(task.getTaskResult());
+ boolean health = BeState.isHealth();
+ if (isStop) {
+ tmpTaskResult.setRetCode(!health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+ } else {
+ tmpTaskResult.setRetCode(health ? 0 : AgentConstants.COMMAND_EXECUTE_UNHEALTH_CODE);
+ }
+
+ return new CommandResult(task.getTaskResult(),
+ task.getTasklog().allStdLog(),
+ task.getTasklog().allErrLog());
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java
new file mode 100644
index 0000000..f25fdd9
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeCommand.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public abstract class FeCommand extends ListenerCommand {
+ @Override
+ public void beforeExecute(CommandType commandType) {
+ if (Objects.isNull(AgentContext.getServiceInstallDir()) || Objects.isNull(AgentContext.getRole()) ||
+ AgentContext.getRole() != Role.FE) {
+ throw new AgentException("service fe not installed");
+ }
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java
new file mode 100644
index 0000000..12dfb4d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallCommand.java
@@ -0,0 +1,61 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+
+public class FeInstallCommand extends Command {
+ private FeInstallCommandRequestBody requestBody;
+
+ public FeInstallCommand(FeInstallCommandRequestBody requestBody) {
+ this.requestBody = requestBody;
+ }
+
+ @Override
+ public Task setupTask() {
+ FeInstallTaskDesc taskDesc = new FeInstallTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getAgentInstallDir() + "/bin/install_fe.sh ";
+ scriptCmd += " --installDir " + requestBody.getInstallDir();
+ scriptCmd += " --url " + requestBody.getPackageUrl();
+ if (requestBody.getMkFeMetadir()) {
+ scriptCmd += " --mkFeMetadir";
+ }
+
+ taskDesc.setScriptCmd(scriptCmd);
+ taskDesc.setInstallDir(requestBody.getInstallDir());
+ return new ScriptTask(taskDesc, new FeInstallTaskHook());
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.INSTALL_FE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java
new file mode 100644
index 0000000..551462c
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskDesc.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+
+public class FeInstallTaskDesc extends ScriptTaskDesc {
+ private String installDir;
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java
new file mode 100644
index 0000000..d2a96ae
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeInstallTaskHook.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import org.apache.doris.manager.agent.exception.AgentException;
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.agent.task.TaskHook;
+import org.apache.logging.log4j.util.Strings;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+
+public class FeInstallTaskHook extends TaskHook<FeInstallTaskDesc> {
+ @Override
+ public void onSuccess(FeInstallTaskDesc taskDesc) {
+ AgentContext.setRole(Role.FE);
+ AgentContext.setServiceInstallDir(taskDesc.getInstallDir());
+
+ String configFile = AgentContext.getServiceInstallDir().endsWith("/") ? AgentContext.getServiceInstallDir() + "conf/fe.conf" : AgentContext.getServiceInstallDir() + "/conf/fe.conf";
+ Properties props = null;
+ try {
+ props = new Properties();
+ props.load(new FileReader(configFile));
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new AgentException("load fe conf file fail:" + configFile);
+ }
+
+ if (props != null && Strings.isNotBlank(props.getProperty("http_port"))) {
+ AgentContext.setHealthCheckPort(Integer.valueOf(props.getProperty("http_port")));
+ } else {
+ AgentContext.setHealthCheckPort(AgentConstants.FE_HTTP_PORT_DEFAULT);
+ }
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java
new file mode 100644
index 0000000..f9eaf2a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStartCommand.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.logging.log4j.util.Strings;
+
+import java.util.Objects;
+
+public class FeStartCommand extends FeCommand {
+ private FeStartCommandRequestBody requestBody;
+
+ public FeStartCommand(FeStartCommandRequestBody requestBody) {
+ this.requestBody = requestBody;
+ }
+
+ @Override
+ public Task setupTask() {
+ ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getServiceInstallDir() + "/bin/start_fe.sh ";
+ if (Objects.nonNull(requestBody)) {
+ if (requestBody.isHelper() && Strings.isNotBlank(requestBody.getHelpHostPort())) {
+ scriptCmd += " --help " + requestBody.getHelpHostPort();
+ }
+ }
+ scriptCmd += " --daemon";
+ taskDesc.setScriptCmd(scriptCmd);
+ return new ScriptTask(taskDesc);
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.START_FE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java
new file mode 100644
index 0000000..d0c4126
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/FeStopCommand.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.register.AgentContext;
+import org.apache.doris.manager.agent.task.ITaskHandlerFactory;
+import org.apache.doris.manager.agent.task.QueuedTaskHandlerFactory;
+import org.apache.doris.manager.agent.task.ScriptTask;
+import org.apache.doris.manager.agent.task.ScriptTaskDesc;
+import org.apache.doris.manager.agent.task.Task;
+import org.apache.doris.manager.agent.task.TaskHandlerFactory;
+import org.apache.doris.manager.common.domain.CommandType;
+
+public class FeStopCommand extends FeCommand {
+ @Override
+ public Task setupTask() {
+ ScriptTaskDesc taskDesc = new ScriptTaskDesc();
+
+ String scriptCmd = AgentContext.getBashBin();
+ scriptCmd += AgentContext.getServiceInstallDir() + "/bin/stop_fe.sh ";
+ taskDesc.setScriptCmd(scriptCmd);
+ return new ScriptTask(taskDesc);
+ }
+
+ @Override
+ public ITaskHandlerFactory setupTaskHandlerFactory() {
+ return TaskHandlerFactory.getTaskHandlerFactory(QueuedTaskHandlerFactory.class);
+ }
+
+ @Override
+ public CommandType setupCommandType() {
+ return CommandType.STOP_FE;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java
new file mode 100644
index 0000000..d6fbade
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/command/ListenerCommand.java
@@ -0,0 +1,27 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.command;
+
+import org.apache.doris.manager.agent.task.Task;
+
+public abstract class ListenerCommand extends Command implements CommandListener {
+ @Override
+ public Task execute() {
+ beforeExecute(commandType);
+ return super.execute();
+ }
+}
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java
new file mode 100644
index 0000000..716986f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/AgentConstants.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.common;
+
+public class AgentConstants {
+ public static final int COMMAND_LOG_PAGE_SIZE = 1000;
+ public static final int COMMAND_EXECUTE_UNHEALTH_CODE = -1;
+
+ public static final int FE_HTTP_PORT_DEFAULT = 8030;
+ public static final int BE_HTTP_PORT_DEFAULT = 8040;
+
+ public static final int COMMAND_HISTORY_SAVE_MAX_COUNT = 100;
+ public static final int TASK_LOG_ROW_MAX_COUNT = 1000;
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java
new file mode 100644
index 0000000..62d1796
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/common/PropertiesUtil.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.common;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Properties;
+
+public class PropertiesUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
+ private static final String DEFAULT_PROPERTIES = "/application.properties";
+
+ /**
+ * get properties key
+ *
+ * @param propKey
+ * @return
+ */
+ public static String getPropValue(String propKey) {
+ try {
+ Properties props = new Properties();
+ InputStream inputStream = PropertiesUtil.class.getResourceAsStream(DEFAULT_PROPERTIES);
+ BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+ props.load(bf);
+ return props.getProperty(propKey);
+ } catch (IOException e) {
+ log.error("get propKey error:", e);
+ }
+ return null;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java
new file mode 100644
index 0000000..b68714d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/AgentException.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.exception;
+
+public class AgentException extends RuntimeException {
+ private static final long serialVersionUID = -1L;
+ private static final Integer DEAFULT_EXCEPTION_STATUS = 500;
+ private int status;
+
+
+ public AgentException(String message) {
+ this(message, DEAFULT_EXCEPTION_STATUS);
+ }
+
+ public AgentException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AgentException(String message, int status) {
+ super(message);
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..b641d8c
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/exception/GlobalExceptionHandler.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.exception;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ @ExceptionHandler(AgentException.class)
+ public RResult handleException(AgentException exception) {
+ log.error(exception.getMessage(), exception);
+ return RResult.error(exception.getStatus(), exception.getMessage());
+ }
+
+ @ExceptionHandler(Throwable.class)
+ public RResult javaExceptionHandler(Exception ex) {
+ log.error("agent error ", ex);
+ return RResult.error(5000, "agent error");
+ }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java
new file mode 100644
index 0000000..d090509
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentContext.java
@@ -0,0 +1,139 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.logging.log4j.util.Strings;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class AgentContext {
+ private static Role role = null;
+ private static String serviceInstallDir = null;
+ private static Integer healthCheckPort = null;
+ private static String agentIp = null;
+ private static Integer agentPort = null;
+ private static String agentServer = null;
+ private static String agentInstallDir = null;
+ private static String bashBin = "/bin/sh ";
+
+ public static void init(String role, String agentIp, Integer agentPort, String agentServer, String dorisHomeDir, String agentInstallDir) {
+ if (Strings.isNotBlank(role) && Objects.nonNull(Role.findByName(role))) {
+ AgentContext.setRole(Role.findByName(role));
+ }
+
+ if (Strings.isNotBlank(agentIp)) {
+ AgentContext.setAgentIp(agentIp);
+ }
+
+ if (Objects.nonNull(agentPort)) {
+ AgentContext.setAgentPort(agentPort);
+ }
+
+ if (Strings.isNotBlank(agentServer)) {
+ AgentContext.setAgentServer(agentServer);
+ }
+
+ if (Strings.isNotBlank(dorisHomeDir)) {
+ AgentContext.setServiceInstallDir(dorisHomeDir);
+ }
+
+ if (Strings.isNotBlank(agentInstallDir)) {
+ AgentContext.setAgentInstallDir(agentInstallDir);
+ }
+ }
+
+
+ public static String getBashBin() {
+ return bashBin;
+ }
+
+ public static void setBashBin(String bashBin) {
+ AgentContext.bashBin = bashBin;
+ }
+
+ public static String getAgentInstallDir() {
+ return agentInstallDir;
+ }
+
+ public static void setAgentInstallDir(String agentInstallDir) {
+ AgentContext.agentInstallDir = agentInstallDir;
+ }
+
+ public static Integer getAgentPort() {
+ return agentPort;
+ }
+
+ public static void setAgentPort(Integer agentPort) {
+ AgentContext.agentPort = agentPort;
+ }
+
+ public static void setRole(Role r) {
+ AgentContext.role = r;
+ }
+
+ public static Role getRole() {
+ return AgentContext.role;
+ }
+
+ public static void setServiceInstallDir(String dir) {
+ AgentContext.serviceInstallDir = dir;
+ }
+
+ public static String getServiceInstallDir() {
+ return AgentContext.serviceInstallDir;
+ }
+
+ public static Integer getHealthCheckPort() {
+ return AgentContext.healthCheckPort;
+ }
+
+ public static void setHealthCheckPort(Integer healthCheckPort) {
+ AgentContext.healthCheckPort = healthCheckPort;
+ }
+
+ public static String getAgentIp() {
+ return agentIp;
+ }
+
+ public static void setAgentIp(String agentIp) {
+ AgentContext.agentIp = agentIp;
+ }
+
+ public static String getAgentServer() {
+ return agentServer;
+ }
+
+ public static void setAgentServer(String agentServer) {
+ AgentContext.agentServer = agentServer;
+ }
+
+ public static Map<String, Object> getContext() {
+ HashMap<String, Object> context = new HashMap<>();
+ context.put("role", AgentContext.role);
+ context.put("serviceInstallDir", AgentContext.serviceInstallDir);
+ context.put("healthCheckPort", AgentContext.healthCheckPort);
+ context.put("agentIp", AgentContext.agentIp);
+ context.put("agentPort", AgentContext.agentPort);
+ context.put("agentServer", AgentContext.agentServer);
+ context.put("agentInstallDir", AgentContext.agentInstallDir);
+ return context;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java
new file mode 100644
index 0000000..97ca69d
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentHeartbeat.java
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public class AgentHeartbeat extends BaseRequest {
+
+ private static final Logger log = LoggerFactory.getLogger(AgentHeartbeat.class);
+ private static final long HEARTBEAT_TIME = 10000l;
+ private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+ public static void start() {
+ scheduler.scheduleWithFixedDelay(() -> {
+ if (!heartbeat()) {
+ log.error("agent heartbeat fail!");
+ } else {
+ log.info("send heartbeat");
+ }
+ }, 0, HEARTBEAT_TIME, TimeUnit.MILLISECONDS);
+ }
+
+ private static boolean heartbeat() {
+ String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/heartbeat";
+ Map<String, Object> map = new HashMap<>();
+ map.put("host", AgentContext.getAgentIp());
+ map.put("port", AgentContext.getAgentPort());
+
+ RResult res = null;
+ try{
+ res = sendRequest(requestUrl, map);
+ }catch (Exception ex){
+ return false;
+ }
+ if (res.getCode() == 0) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java
new file mode 100644
index 0000000..e6a32c4
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRegister.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AgentRegister extends BaseRequest {
+
+ public static boolean register() {
+
+ String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/register";
+ Map<String, Object> map = new HashMap<>();
+ map.put("host", AgentContext.getAgentIp());
+ map.put("port", AgentContext.getAgentPort());
+
+ RResult res = null;
+ try{
+ res = sendRequest(requestUrl, map);
+ }catch (Exception ex){
+ return false;
+ }
+ if (res.getCode() == 0) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java
new file mode 100644
index 0000000..46f8d5f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/AgentRole.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.RResult;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * query agent role
+ **/
+public class AgentRole extends BaseRequest {
+
+ public static String queryRole() {
+ String requestUrl = "http://" + AgentContext.getAgentServer() + "/server/agentRole";
+ Map<String, Object> map = new HashMap<>();
+ map.put("host", AgentContext.getAgentIp());
+
+ RResult resultResp = sendRequest(requestUrl, map);
+ if (resultResp == null) {
+ return null;
+ }
+ return String.valueOf(resultResp.getData());
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java
new file mode 100644
index 0000000..e39ebf6
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/ApplicationOption.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.kohsuke.args4j.Option;
+
+public class ApplicationOption {
+ @Option(name = "--agentIp", required = true, usage = "Specify agent agentIp")
+ public String agentIp;
+
+ @Option(name = "--agentServer", required = true, usage = "Specify agent agentServer agentIp:port")
+ public String agentServer;
+
+ @Option(name = "--dorisHomeDir", usage = "Specify service home dir")
+ public String dorisHomeDir;
+
+ @Option(name = "--role", usage = "Specify service role")
+ public String role;
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java
new file mode 100644
index 0000000..3601cec
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BaseRequest.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class BaseRequest {
+
+ private static final Logger log = LoggerFactory.getLogger(BaseRequest.class);
+
+ public static RResult sendRequest(String requestUrl, Map<String, Object> params) {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPost httpPost = new HttpPost(requestUrl);
+
+ RequestConfig requestConfig = RequestConfig.custom().
+ setConnectTimeout(5000).
+ setConnectionRequestTimeout(5000)
+ .setSocketTimeout(5000).build();
+ httpPost.setConfig(requestConfig);
+
+ httpPost.setEntity(new StringEntity(JSON.toJSONString(params), "utf-8"));
+ httpPost.addHeader("Content-Type", "application/json");
+
+ CloseableHttpResponse response = null;
+ String result = "";
+
+ try {
+ response = httpclient.execute(httpPost);
+ result = EntityUtils.toString(response.getEntity());
+ } catch (IOException e) {
+ log.error("request url error:{},param:{}",requestUrl,params,e);
+ throw new RuntimeException(e);
+ }
+
+ RResult res = JSON.parseObject(result, RResult.class);
+ return res;
+ }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java
new file mode 100644
index 0000000..cadb973
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/BeState.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class BeState {
+ public static boolean isHealth() {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+
+ String requestUrl = "http://" + AgentContext.getAgentIp() + ":" + AgentContext.getHealthCheckPort() + "/api/health";
+
+ HttpGet httpget = new HttpGet(requestUrl);
+
+ RequestConfig requestConfig = RequestConfig.custom().
+ setConnectTimeout(5000).
+ setConnectionRequestTimeout(5000)
+ .setSocketTimeout(5000).build();
+ httpget.setConfig(requestConfig);
+
+ CloseableHttpResponse response = null;
+ String result = "";
+
+ try {
+ response = httpclient.execute(httpget);
+ result = EntityUtils.toString(response.getEntity());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ JSONObject jsonObject = JSON.parseObject(result);
+ if (jsonObject == null) {
+ return false;
+ }
+
+ String status = jsonObject.getString("status");
+ if ("ok".equalsIgnoreCase(status)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java
new file mode 100644
index 0000000..3a1b23f
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/FeState.java
@@ -0,0 +1,69 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class FeState {
+ public static boolean isHealth() {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+
+ String requestUrl = "http://" + AgentContext.getAgentIp() + ":" + AgentContext.getHealthCheckPort() + "/api/bootstrap";
+
+ HttpGet httpget = new HttpGet(requestUrl);
+
+ RequestConfig requestConfig = RequestConfig.custom().
+ setConnectTimeout(5000).
+ setConnectionRequestTimeout(5000)
+ .setSocketTimeout(5000).build();
+ httpget.setConfig(requestConfig);
+
+ CloseableHttpResponse response = null;
+ String result = "";
+
+ try {
+ response = httpclient.execute(httpget);
+ result = EntityUtils.toString(response.getEntity());
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ JSONObject jsonObject = JSON.parseObject(result);
+ if (jsonObject == null) {
+ return false;
+ }
+
+ String code = jsonObject.getString("code");
+ String msg = jsonObject.getString("msg");
+ String status = jsonObject.getString("status");
+ if (("0".equals(code) && "success".equalsIgnoreCase(msg)) || "OK".equalsIgnoreCase(status)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java
new file mode 100644
index 0000000..2f9002e
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/register/StateService.java
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.register;
+
+import org.apache.doris.manager.common.domain.Role;
+
+import java.util.Objects;
+
+public class StateService {
+
+ public static boolean isHealth() {
+ Role role = AgentContext.getRole();
+ if (Objects.isNull(role)) {
+ throw new RuntimeException("the service is not installed");
+ }
+ switch (role) {
+ case FE:
+ return FeState.isHealth();
+ case BE:
+ return BeState.isHealth();
+ default:
+ throw new RuntimeException("unkonw role:" + role);
+ }
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java
new file mode 100644
index 0000000..9303ca3
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/AbsAsyncTaskHandler.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+
+public abstract class AbsAsyncTaskHandler extends TaskHandler {
+
+ @Override
+ public void doHandle(Task task) {
+ task.getTaskResult().setTaskState(TaskState.QUEUED);
+
+ TaskContext.register(task);
+ getExecutorService().submit(new Runnable() {
+ @Override
+ public void run() {
+ task.executeTask();
+ }
+ });
+ }
+
+ public abstract ExecutorService getExecutorService();
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java
new file mode 100644
index 0000000..7913676
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskHandlerFactory.java
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public interface ITaskHandlerFactory {
+ TaskHandler createTaskHandler();
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java
new file mode 100644
index 0000000..d5dd206
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ITaskLog.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import javafx.util.Pair;
+
+import java.util.List;
+
+public interface ITaskLog {
+ Pair<Integer, List<String>> stdLog(int offset, int size);
+
+ List<String> errLog(int offset, int size);
+
+ void appendStdLog(String log);
+
+ void appendErrLog(String log);
+
+ List<String> allStdLog();
+
+ List<String> allErrLog();
+}
+
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java
new file mode 100644
index 0000000..e81d737
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/LRU.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LRU<K, V> {
+ private final float loadFactory = 0.75f;
+ private LinkedHashMap<K, V> map;
+
+ public LRU(int maxCacheSize) {
+ int capacity = (int) Math.ceil(maxCacheSize / this.loadFactory) + 1;
+ map = new LinkedHashMap<K, V>(capacity, loadFactory, false) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > maxCacheSize;
+ }
+ };
+ }
+
+ public void put(K key, V value) {
+ map.put(key, value);
+ }
+
+ public V get(K key) {
+ return map.get(key);
+ }
+
+ public void remove(K key) {
+ map.remove(key);
+ }
+
+ public boolean contain(K key) {
+ return map.containsKey(key);
+ }
+
+ public int size() {
+ return map.size();
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java
new file mode 100644
index 0000000..3fcebdf
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandler.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+
+public class QueuedTaskHandler extends AbsAsyncTaskHandler {
+ @Override
+ public ExecutorService getExecutorService() {
+ return TaskExecutorService.getSingleThreadExecutor();
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java
new file mode 100644
index 0000000..9246302
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/QueuedTaskHandlerFactory.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class QueuedTaskHandlerFactory implements ITaskHandlerFactory {
+ private static TaskHandler instance = null;
+
+ @Override
+ public TaskHandler createTaskHandler() {
+ if (instance == null) {
+ synchronized (QueuedTaskHandlerFactory.class) {
+ if (instance == null)
+ instance = new QueuedTaskHandler();
+ }
+ }
+ return instance;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java
new file mode 100644
index 0000000..41c6803
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTask.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+public class ScriptTask extends Task<ScriptTaskDesc> {
+
+ public ScriptTask(ScriptTaskDesc taskDesc) {
+ super(taskDesc, new TaskLruLog());
+ }
+
+ public ScriptTask(ScriptTaskDesc taskDesc, TaskHook taskHook) {
+ super(taskDesc, new TaskLruLog(), taskHook);
+ }
+
+ @Override
+ protected int execute() {
+ try {
+ Runtime rt = Runtime.getRuntime();
+ Process proc = rt.exec(taskDesc.getScriptCmd());
+ BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
+
+
+ String s = null;
+ while ((s = stdInput.readLine()) != null) {
+ getTasklog().appendStdLog(s);
+ }
+
+ while ((s = stdError.readLine()) != null) {
+ getTasklog().appendErrLog(s);
+ }
+
+ int exitVal = proc.waitFor();
+ return exitVal;
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return -1;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java
new file mode 100644
index 0000000..b10a877
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/ScriptTaskDesc.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class ScriptTaskDesc extends TaskDesc {
+ private String scriptCmd;
+
+ public String getScriptCmd() {
+ return scriptCmd;
+ }
+
+ public void setScriptCmd(String scriptCmd) {
+ this.scriptCmd = scriptCmd;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java
new file mode 100644
index 0000000..69aaa26
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandler.java
@@ -0,0 +1,25 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class SyncTaskHandler extends TaskHandler {
+
+ @Override
+ public void doHandle(Task task) {
+ task.executeTask();
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java
new file mode 100644
index 0000000..2db5a13
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/SyncTaskHandlerFactory.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public class SyncTaskHandlerFactory implements ITaskHandlerFactory {
+ private static TaskHandler instance = null;
+
+ @Override
+ public TaskHandler createTaskHandler() {
+ if (instance == null) {
+ synchronized (SyncTaskHandlerFactory.class) {
+ if (instance == null)
+ instance = new SyncTaskHandler();
+ }
+ }
+ return instance;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java
new file mode 100644
index 0000000..884317a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/Task.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+import java.util.UUID;
+
+public abstract class Task<T extends TaskDesc> {
+ protected T taskDesc;
+ private TaskResult taskResult;
+ private ITaskLog tasklog;
+ private TaskHook taskHook;
+
+
+ private Task(T taskDesc) {
+ this.taskDesc = taskDesc;
+ this.taskResult = new TaskResult();
+ this.taskResult.setTaskId(UUID.randomUUID().toString().replace("-", ""));
+ }
+
+ public Task(T taskDesc, ITaskLog taskLruLog) {
+ this(taskDesc);
+ this.tasklog = taskLruLog;
+ }
+
+ public Task(T taskDesc, ITaskLog taskLruLog, TaskHook taskHook) {
+ this(taskDesc);
+ this.tasklog = taskLruLog;
+ this.taskHook = taskHook;
+ }
+
+
+ public ITaskLog getTasklog() {
+ return tasklog;
+ }
+
+ public String getTaskId() {
+ return this.taskResult.getTaskId();
+ }
+
+ public TaskResult getTaskResult() {
+ return taskResult;
+ }
+
+ public TaskResult executeTask() {
+ this.taskResult.setStartTime(new Date());
+ this.taskResult.setTaskState(TaskState.RUNNING);
+ int code = -501;
+ try {
+ code = execute();
+ if (0 == code && taskHook != null) {
+ taskHook.onSuccess(taskDesc);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ } finally {
+ this.taskResult.setEndTime(new Date());
+ this.taskResult.setRetCode(code);
+ this.taskResult.setTaskState(TaskState.FINISHED);
+ }
+ return this.taskResult;
+ }
+
+ public T getTaskDesc() {
+ return taskDesc;
+ }
+
+ protected abstract int execute();
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java
new file mode 100644
index 0000000..967ab6a
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskContext.java
@@ -0,0 +1,35 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+
+public class TaskContext {
+ private static final LRU<String, Task> taskLRU = new LRU<>(AgentConstants.COMMAND_HISTORY_SAVE_MAX_COUNT);
+
+ public static synchronized void register(Task task) {
+ taskLRU.put(task.getTaskId(), task);
+ }
+
+ public static synchronized void unregister(Task task) {
+ taskLRU.remove(task.getTaskId());
+ }
+
+ public static synchronized Task getTaskByTaskId(String taskId) {
+ return taskLRU.get(taskId);
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java
new file mode 100644
index 0000000..5700811
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskDesc.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public abstract class TaskDesc {
+ private String taskName;
+
+ public String getTaskName() {
+ return taskName;
+ }
+
+ public void setTaskName(String taskName) {
+ this.taskName = taskName;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java
new file mode 100644
index 0000000..8afb633
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskExecutorService.java
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class TaskExecutorService {
+ private static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
+
+ public static ExecutorService getSingleThreadExecutor() {
+ return singleThreadExecutor;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java
new file mode 100644
index 0000000..6488f61
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandler.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+
+public abstract class TaskHandler {
+ public void handle(Task task) {
+ task.getTaskResult().setSubmitTime(new Date());
+ doHandle(task);
+ }
+
+ public abstract void doHandle(Task task);
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java
new file mode 100644
index 0000000..eba7df4
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHandlerFactory.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.exception.AgentException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class TaskHandlerFactory {
+ private static Map<Class, ITaskHandlerFactory> factoryInstanceMap = new ConcurrentHashMap<>();
+
+ public static ITaskHandlerFactory getTaskHandlerFactory(Class<? extends ITaskHandlerFactory> className) {
+ synchronized (factoryInstanceMap) {
+ if (!factoryInstanceMap.containsKey(className)) {
+ ITaskHandlerFactory factory = null;
+ try {
+ Class<? extends ITaskHandlerFactory> factoryClass = (Class<? extends ITaskHandlerFactory>) Class.forName(className.getName());
+ factory = factoryClass.newInstance();
+ factoryInstanceMap.put(className, factory);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AgentException("failed create factory:" + className.getName());
+ }
+ return factory;
+ }
+ return factoryInstanceMap.get(className);
+ }
+ }
+
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java
new file mode 100644
index 0000000..ccae3a5
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskHook.java
@@ -0,0 +1,5 @@
+package org.apache.doris.manager.agent.task;
+
+public abstract class TaskHook<T extends TaskDesc> {
+ public abstract void onSuccess(T taskDesc);
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java
new file mode 100644
index 0000000..d4478d0
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskLruLog.java
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import org.apache.doris.manager.agent.common.AgentConstants;
+import javafx.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskLruLog implements ITaskLog {
+ private LRU<Integer, String> stdlogs;
+ private LRU<Integer, String> errlogs;
+
+ private int currentStdPage = 0;
+ private int currentErrPage = 0;
+
+
+ public TaskLruLog() {
+ this(AgentConstants.TASK_LOG_ROW_MAX_COUNT, AgentConstants.TASK_LOG_ROW_MAX_COUNT);
+ }
+
+ public TaskLruLog(int maxStdCacheSize, int maxErrCacheSize) {
+ this.stdlogs = new LRU<>(maxStdCacheSize);
+ this.errlogs = new LRU<>(maxErrCacheSize);
+ }
+
+ @Override
+ public Pair<Integer, List<String>> stdLog(int offset, int size) {
+ int count = 0;
+ ArrayList<String> list = new ArrayList<>();
+ String temp = null;
+ if (offset > stdlogs.size()) {
+ return new Pair(stdlogs.size() - 1 > 0 ? stdlogs.size() - 1 : 0, list);
+ }
+
+ while (count < size && offset + count < stdlogs.size()) {
+ if ((temp = stdlogs.get(offset + count)) != null) {
+ list.add(temp);
+ }
+ count++;
+ }
+ Pair<Integer, List<String>> pair = new Pair(offset + count, list);
+ return pair;
+ }
+
+ @Override
+ public List<String> errLog(int offset, int size) {
+ int count = 0;
+ ArrayList<String> list = new ArrayList<>();
+ String temp = null;
+ while (count < size) {
+ if ((temp = errlogs.get(offset + count)) != null) {
+ list.add(temp);
+ }
+ count++;
+ }
+ return list;
+ }
+
+ public List<String> allStdLog() {
+ return stdLog(0, stdlogs.size()).getValue();
+ }
+
+ public List<String> allErrLog() {
+ return errLog(0, errlogs.size());
+ }
+
+ @Override
+ public void appendStdLog(String log) {
+ stdlogs.put(currentStdPage++, log);
+ }
+
+ @Override
+ public void appendErrLog(String log) {
+ errlogs.put(currentErrPage++, log);
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java
new file mode 100644
index 0000000..a4138e8
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskResult.java
@@ -0,0 +1,88 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+import java.util.Date;
+
+public class TaskResult {
+ private String taskId;
+ private Date submitTime;
+ private Date startTime;
+ private Date endTime;
+ private TaskState taskState;
+ private Integer retCode;
+
+ public TaskResult() {
+ }
+
+ public TaskResult(TaskResult taskResult) {
+ this.taskId = taskResult.getTaskId();
+ this.submitTime = taskResult.getSubmitTime();
+ this.startTime = taskResult.getStartTime();
+ this.endTime = taskResult.getEndTime();
+ this.taskState = taskResult.getTaskState();
+ this.retCode = taskResult.getRetCode();
+ }
+
+ public TaskState getTaskState() {
+ return taskState;
+ }
+
+ public void setTaskState(TaskState taskState) {
+ this.taskState = taskState;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getTaskId() {
+ return taskId;
+ }
+
+ public void setTaskId(String taskId) {
+ this.taskId = taskId;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ public Integer getRetCode() {
+ return retCode;
+ }
+
+ public void setRetCode(Integer retCode) {
+ this.retCode = retCode;
+ }
+
+ public Date getSubmitTime() {
+ return submitTime;
+ }
+
+ public void setSubmitTime(Date submitTime) {
+ this.submitTime = submitTime;
+ }
+}
diff --git a/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java
new file mode 100644
index 0000000..1fbb71b
--- /dev/null
+++ b/manager/dm-agent/src/main/java/org/apache/doris/manager/agent/task/TaskState.java
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.agent.task;
+
+public enum TaskState {
+ // Task has been queued for execution by the driver
+ INITIALIZED,
+ // Task has been queued for execution by the driver
+ QUEUED,
+ // Task is currently running
+ RUNNING,
+ // Task has completed
+ FINISHED,
+ // Task state is unkown
+ UNKNOWN
+}
diff --git a/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh b/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh
new file mode 100755
index 0000000..ff3bbfa
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/agent_start.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+ -n $0 \
+ -o '' \
+ -l 'server:' \
+ -l 'agent:' \
+ -- "$@")
+
+eval set -- "$OPTS"
+
+#host:port
+SERVER=
+AGENT=
+while true; do
+ case "$1" in
+ --server) SERVER=$2 ; shift 2;;
+ --agent) AGENT=$2 ; shift 2;;
+ --) shift ; break ;;
+ *) echo "Internal error" ; exit 1 ;;
+ esac
+done
+
+if [ x"$SERVER" == x"" ]; then
+ echo "--server ip can not empty!"
+ exit 1
+fi
+
+if [ x"$AGENT" == x"" ]; then
+ echo "--agent ip can not empty!"
+ exit 1
+fi
+export AGENT_HOME=`cd "$curdir/.."; pwd`
+
+#
+# JAVA_OPTS
+# SERVER_PARAMS
+# LOG_DIR
+# PID_DIR
+export JAVA_OPTS="-Xmx1024m"
+export SERVER_PARAMS="--agentServer=$SERVER --agentIp=$AGENT"
+export LOG_DIR="$AGENT_HOME/log"
+export PID_DIR=`cd "$curdir"; pwd`
+
+# java
+if [ "$JAVA_HOME" = "" ]; then
+ echo "Error: JAVA_HOME is not set."
+ exit 1
+fi
+JAVA=$JAVA_HOME/bin/java
+
+# need check and create if the log directory existed before outing message to the log file.
+if [ ! -d $LOG_DIR ]; then
+ mkdir -p $LOG_DIR
+fi
+
+pidfile=$PID_DIR/agent.pid
+
+if [ -f $pidfile ]; then
+ if kill -0 `cat $pidfile` > /dev/null 2>&1; then
+ echo agent running as process `cat $pidfile`. Stop it first.
+ exit 1
+ fi
+fi
+
+nohup $JAVA $JAVA_OPTS -jar ${AGENT_HOME}/lib/dm-agent.jar $SERVER_PARAMS >> $LOG_DIR/agent.out 2>&1 &
+echo `date` >> $LOG_DIR/agent.out
+
+echo $! > $pidfile
diff --git a/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh b/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh
new file mode 100755
index 0000000..e651584
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/agent_stop.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export AGENT_HOME=`cd "$curdir/.."; pwd`
+export PID_DIR=`cd "$curdir"; pwd`
+
+pidfile=$PID_DIR/agent.pid
+
+if [ -f $pidfile ]; then
+ pid=`cat $pidfile`
+ pidcomm=`ps -p $pid -o comm=`
+
+ if [ "java" != "$pidcomm" ]; then
+ echo "ERROR: pid process may not be agent. "
+ fi
+
+ if kill -9 $pid > /dev/null 2>&1; then
+ echo "stop $pidcomm, and remove pid file. "
+ rm $pidfile
+ fi
+fi
+
diff --git a/manager/dm-agent/src/main/resources/agent/bin/install_be.sh b/manager/dm-agent/src/main/resources/agent/bin/install_be.sh
new file mode 100755
index 0000000..a90725b
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/install_be.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+ -n $0 \
+ -o '' \
+ -l 'url:' \
+ -l 'installDir:' \
+ -l 'mkBeStorageDir' \
+ -- "$@")
+
+eval set -- "$OPTS"
+
+URL=
+DORIS_HOME=
+MKDIR_BE_STORAGE_DIR=0
+while true; do
+ case "$1" in
+ --url) URL=$2 ; shift 2;;
+ --installDir) DORIS_HOME=$2 ; shift 2;;
+ --mkBeStorageDir) MKDIR_BE_STORAGE_DIR=1 ; shift ;;
+ --) shift ; break ;;
+ *) echo "Internal error" ; exit 1 ;;
+ esac
+done
+
+if [ x"$DORIS_HOME" == x"" ]; then
+ echo "--installDir can not empty!"
+ exit 1
+fi
+
+if [ x"$URL" == x"" ]; then
+ echo "--url can not empty!"
+ exit 1
+fi
+
+if [ ! -d $DORIS_HOME ]; then
+ mkdir -p $DORIS_HOME
+fi
+
+wget $URL -O doris-be.tar.gz --quiet
+if [ $? -ne 0 ] ;then exit 1;fi
+
+tar -zxvf doris-be.tar.gz -C $DORIS_HOME
+if [ $? -ne 0 ] ;then exit 1;fi
+
+if [[ ${MKDIR_BE_STORAGE_DIR} -eq 1 ]] && [[ ! -d "$DORIS_HOME/storage" ]]; then
+ mkdir $DORIS_HOME/storage
+fi
+if [ $? -ne 0 ] ;then exit 1;fi
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh b/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh
new file mode 100755
index 0000000..36f5825
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/agent/bin/install_fe.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+OPTS=$(getopt \
+ -n $0 \
+ -o '' \
+ -l 'url:' \
+ -l 'installDir:' \
+ -l 'mkFeMetadir' \
+ -- "$@")
+
+eval set -- "$OPTS"
+
+URL=
+DORIS_HOME=
+MKDIR_FE_META_DIR=0
+while true; do
+ case "$1" in
+ --url) URL=$2 ; shift 2;;
+ --installDir) DORIS_HOME=$2 ; shift 2;;
+ --mkFeMetadir) MKDIR_FE_META_DIR=1 ; shift ;;
+ --) shift ; break ;;
+ *) echo "Internal error" ; exit 1 ;;
+ esac
+done
+
+if [ x"$DORIS_HOME" == x"" ]; then
+ echo "--installDir can not empty!"
+ exit 1
+fi
+
+if [ x"$URL" == x"" ]; then
+ echo "--url can not empty!"
+ exit 1
+fi
+
+if [ ! -d $DORIS_HOME ]; then
+ mkdir -p $DORIS_HOME
+fi
+
+wget $URL -O doris-fe.tar.gz --quiet
+if [ $? -ne 0 ] ;then exit 1;fi
+
+tar -zxvf doris-fe.tar.gz -C $DORIS_HOME
+if [ $? -ne 0 ] ;then exit 1;fi
+
+if [[ ${MKDIR_FE_META_DIR} -eq 1 ]] && [[ ! -d "$DORIS_HOME/doris-meta" ]]; then
+ mkdir $DORIS_HOME/doris-meta
+fi
+if [ $? -ne 0 ] ;then exit 1;fi
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/application.properties b/manager/dm-agent/src/main/resources/application.properties
new file mode 100644
index 0000000..542e0e3
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/application.properties
@@ -0,0 +1 @@
+server.port=9602
\ No newline at end of file
diff --git a/manager/dm-agent/src/main/resources/logback-spring.xml b/manager/dm-agent/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..22cd80a
--- /dev/null
+++ b/manager/dm-agent/src/main/resources/logback-spring.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false">
+ <springProperty scope="context" name="springAppName" source="spring.application.name" defaultValue="agent" />
+ <property name="LOG_HOME" value="./log"/>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+ </encoder>
+ </appender>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <FileNamePattern>${LOG_HOME}/${springAppName}.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+ <MaxHistory>30</MaxHistory>
+ <maxFileSize>50MB</maxFileSize>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="INFO">
+ <appender-ref ref="STDOUT" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/manager/dm-common/pom.xml b/manager/dm-common/pom.xml
new file mode 100644
index 0000000..b9dd5e1
--- /dev/null
+++ b/manager/dm-common/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>doris-manager</artifactId>
+ <groupId>org.apache.doris</groupId>
+ <version>1.0.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dm-common</artifactId>
+ <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java
new file mode 100644
index 0000000..662c67c
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/BeInstallCommandRequestBody.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class BeInstallCommandRequestBody {
+ private String installDir;
+ private String packageUrl;
+ private boolean mkBeStorageDir = false;
+
+
+ public boolean isMkBeStorageDir() {
+ return mkBeStorageDir;
+ }
+
+ public void setMkBeStorageDir(boolean mkBeStorageDir) {
+ this.mkBeStorageDir = mkBeStorageDir;
+ }
+
+ public String getPackageUrl() {
+ return packageUrl;
+ }
+
+ public void setPackageUrl(String packageUrl) {
+ this.packageUrl = packageUrl;
+ }
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java
new file mode 100644
index 0000000..999990e
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandRequest.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class CommandRequest {
+ private String commandType;
+ private String body;
+
+ public String getCommandType() {
+ return commandType;
+ }
+
+ public void setCommandType(String commandType) {
+ this.commandType = commandType;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java
new file mode 100644
index 0000000..25738bd
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/CommandType.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public enum CommandType {
+ INSTALL_FE,
+
+ INSTALL_BE,
+
+ START_FE,
+
+ STOP_FE,
+
+ START_BE,
+
+ STOP_BE;
+
+ public static CommandType findByName(String name) {
+ for (CommandType type : CommandType.values()) {
+ if (type.name().equals(name)) {
+ return type;
+ }
+ }
+ return null;
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java
new file mode 100644
index 0000000..0a68d62
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeInstallCommandRequestBody.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class FeInstallCommandRequestBody {
+ private String packageUrl;
+ private String installDir;
+ private Boolean mkFeMetadir = false;
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+
+ public String getPackageUrl() {
+ return packageUrl;
+ }
+
+ public void setPackageUrl(String packageUrl) {
+ this.packageUrl = packageUrl;
+ }
+
+ public Boolean getMkFeMetadir() {
+ return mkFeMetadir;
+ }
+
+ public void setMkFeMetadir(Boolean mkFeMetadir) {
+ this.mkFeMetadir = mkFeMetadir;
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java
new file mode 100644
index 0000000..894c7e3
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/FeStartCommandRequestBody.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public class FeStartCommandRequestBody {
+ private boolean helper;
+ private String helpHostPort;
+
+ public boolean isHelper() {
+ return helper;
+ }
+
+ public void setHelper(boolean helper) {
+ this.helper = helper;
+ }
+
+ public String getHelpHostPort() {
+ return helpHostPort;
+ }
+
+ public void setHelpHostPort(String helpHostPort) {
+ this.helpHostPort = helpHostPort;
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java
new file mode 100644
index 0000000..3818543
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/RResult.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+public class RResult extends HashMap<String, Object> {
+ private static final long serialVersionUID = 1L;
+ private static final int CODE_SUCCESS = 0;
+ public static final String CODE_TAG = "code";
+ public static final String MSG_TAG = "msg";
+ public static final String DATA_TAG = "data";
+
+ public RResult() {
+ }
+
+ public RResult(int code, String msg) {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ }
+
+ public RResult(int code, String msg, Object data) {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ if (!Objects.isNull(data)) {
+ super.put(DATA_TAG, data);
+ }
+ }
+
+ public static RResult success() {
+ return RResult.success("success");
+ }
+
+ public static RResult success(Object data) {
+ return RResult.success("success", data);
+ }
+
+ public static RResult success(String msg) {
+ return RResult.success(msg, null);
+ }
+
+ public static RResult success(String msg, Object data) {
+ return new RResult(CODE_SUCCESS, msg, data);
+ }
+
+ public static RResult error() {
+ return RResult.error("fail");
+ }
+
+ public static RResult error(String msg) {
+ return RResult.error(msg, null);
+ }
+
+ public static RResult error(String msg, Object data) {
+ return new RResult(CODE_SUCCESS, msg, data);
+ }
+
+ public static RResult error(int code, String msg) {
+ return new RResult(code, msg, null);
+ }
+
+ public Object getData() {
+ return this.get("data");
+ }
+
+ public int getCode() {
+ return (int) this.get("code");
+ }
+}
diff --git a/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java
new file mode 100644
index 0000000..683d7ac
--- /dev/null
+++ b/manager/dm-common/src/main/java/org/apache/doris/manager/common/domain/Role.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.common.domain;
+
+public enum Role {
+ FE,
+ BE;
+
+ public static Role findByName(String name) {
+ for (Role type : Role.values()) {
+ if (type.name().equals(name)) {
+ return type;
+ }
+ }
+ return null;
+ }
+}
diff --git a/manager/dm-server/pom.xml b/manager/dm-server/pom.xml
new file mode 100644
index 0000000..cda05a9
--- /dev/null
+++ b/manager/dm-server/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>doris-manager</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dm-server</artifactId>
+ <packaging>jar</packaging>
+
+ <name>dm-server</name>
+
+ <properties>
+ <java.version>1.8</java.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-jdbc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-common</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.9</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5.6</version>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>1.2.76</version>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java
new file mode 100644
index 0000000..af7801a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/DmServerApplication.java
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DmServerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DmServerApplication.class, args);
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java
new file mode 100644
index 0000000..b83e88b
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentCache.java
@@ -0,0 +1,68 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * agent host port cache
+ **/
+@Component
+public class AgentCache {
+
+ private static final Map<String, AgentEntity> hostAgentCache = new ConcurrentHashMap<>();
+
+ @Autowired
+ private ServerDao serverDao;
+
+ @PostConstruct
+ public void init() {
+ loadAgents();
+ }
+
+ private void loadAgents() {
+ List<AgentEntity> agentEntities = serverDao.queryAgentNodes(new ArrayList<>());
+ if (agentEntities != null && !agentEntities.isEmpty()) {
+ Map<String, AgentEntity> agentsMap = agentEntities.stream().collect(Collectors.toMap(AgentEntity::getHost, v -> v));
+ hostAgentCache.putAll(agentsMap);
+ }
+ }
+
+ /**
+ * get agent from cache by host
+ */
+ public AgentEntity agentInfo(String host) {
+ return hostAgentCache.get(host);
+ }
+
+ /**
+ * put agent to cache
+ */
+ public void putAgent(AgentEntity agent) {
+ hostAgentCache.put(agent.getHost(),agent);
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java
new file mode 100644
index 0000000..9808ab4
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentHeatbeatRunner.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * agent status check
+ **/
+@Component
+public class AgentHeatbeatRunner implements ApplicationRunner {
+
+ private static final Logger log = LoggerFactory.getLogger(AgentHeatbeatRunner.class);
+ private static final long HEALTH_TIME = 60 * 1000l;
+ private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+ @Autowired
+ private ServerProcess serverProcess;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ this.scheduler.scheduleWithFixedDelay(() -> {
+ try {
+ heartbeatCheck();
+ } catch (Exception ex) {
+ log.error("heartbeat check fail:", ex);
+ }
+ }, 0, HEALTH_TIME, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * The last heartbeat time exceeds the HEALTH_TIME and is recognized as unhealthy
+ */
+ private void heartbeatCheck() {
+ long currTime = System.currentTimeMillis();
+ List<AgentEntity> unHealthAgent = new ArrayList<>();
+ List<AgentEntity> agents = serverProcess.agentList();
+ for (AgentEntity agent : agents) {
+ Date lastReportedTime = agent.getLastReportedTime();
+ long diff = HEALTH_TIME + 1;
+ if(lastReportedTime != null){
+ diff = currTime - lastReportedTime.getTime();
+ }
+ if (diff > HEALTH_TIME) {
+ AgentEntity agentEntity = new AgentEntity();
+ agentEntity.setId(agent.getId());
+ agentEntity.setStatus(AgentStatus.STOP.name());
+ unHealthAgent.add(agentEntity);
+ log.warn("agent {} is unhealthly", agent.getHost());
+ }
+ }
+ if (!unHealthAgent.isEmpty()) {
+ serverProcess.updateBatchAgentStatus(unHealthAgent);
+ }
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java
new file mode 100644
index 0000000..2043bb8
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/agent/AgentRest.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.agent;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+/**
+ * agent rest api
+ **/
+@Component
+public class AgentRest {
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ private static final String AGENT_COMMAND_EXEC = "http://%s:%s/command/execute";
+ private static final String AGENT_TASK_INFO = "http://%s:%s/command/result?taskId={taskId}";
+ private static final String AGENT_TASK_STD_LOG = "http://%s:%s/command/stdlog?taskId={taskId}&offset={offset}";
+ private static final String AGENT_TASK_ERR_LOG = "http://%s:%s/command/errlog?taskId={taskId}&offset={offset}";
+
+ public RResult commandExec(String host, Integer port, Object param) {
+ String restUrl = String.format(AGENT_COMMAND_EXEC, host, port);
+ RResult result = restTemplate.postForObject(restUrl, param, RResult.class);
+ return result;
+ }
+
+ public RResult taskInfo(String host, Integer port, Map<String, Object> param) {
+ String restUrl = String.format(AGENT_TASK_INFO, host, port);
+ RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+ return result;
+ }
+
+ public RResult taskStdLog(String host, Integer port, Map<String, Object> param) {
+ String restUrl = String.format(AGENT_TASK_STD_LOG, host, port);
+ RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+ return result;
+ }
+
+ public RResult taskErrLog(String host, Integer port, Map<String, Object> param) {
+ String restUrl = String.format(AGENT_TASK_ERR_LOG, host, port);
+ RResult result = restTemplate.getForObject(restUrl, RResult.class, param);
+ return result;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java
new file mode 100644
index 0000000..c6e82fa
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/config/RestTemplateConfig.java
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+
+@Configuration
+public class RestTemplateConfig {
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java
new file mode 100644
index 0000000..8da4e9e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/AgentStatus.java
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public enum AgentStatus {
+ RUNNING,
+ STOP;
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java
new file mode 100644
index 0000000..49d7c9b
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/CmdTypeEnum.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public enum CmdTypeEnum {
+ START,
+ STOP,
+ RESTART;
+
+ public static CmdTypeEnum findByName(String name) {
+ for (CmdTypeEnum type : CmdTypeEnum.values()) {
+ if (type.name().equals(name)) {
+ return type;
+ }
+ }
+ return null;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java
new file mode 100644
index 0000000..eabfc8f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/constants/Constants.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.constants;
+
+public class Constants {
+
+ public static String KEY_SERVER_PORT = "server.port";
+ public static String KEY_DORIS_AGENT_INSTALL_DIR = "doris.manager.agent.install.dir";
+ public static String KEY_DORIS_AGENT_START_SCRIPT = "doris.manager.agent.start-script";
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java
new file mode 100644
index 0000000..b182cc7
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/AgentController.java
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.controller;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+import org.apache.doris.manager.server.service.ServerAgent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/agent")
+public class AgentController {
+
+ @Autowired
+ private ServerAgent serverAgent;
+
+ /**
+ * install doris
+ */
+ @RequestMapping(value = "/installDoris", method = RequestMethod.POST)
+ public RResult install(@RequestBody DorisInstallReq installReq) {
+ return RResult.success(serverAgent.install(installReq));
+ }
+
+ /**
+ * request agent:start stop fe/be
+ */
+ @RequestMapping(value = "/execute", method = RequestMethod.POST)
+ public RResult execute(@RequestBody DorisExecReq dorisExec) {
+ return RResult.success(serverAgent.execute(dorisExec));
+ }
+
+ /**
+ * request task detail
+ */
+ @RequestMapping(value = "/task", method = RequestMethod.POST)
+ public RResult taskInfo(@RequestBody TaskInfoReq taskInfo) {
+ return serverAgent.taskInfo(taskInfo);
+ }
+
+ /**
+ * request task stdout log
+ */
+ @RequestMapping(value = "/stdlog", method = RequestMethod.POST)
+ public RResult taskStdlog(@RequestBody TaskLogReq taskInfo) {
+ return serverAgent.taskStdlog(taskInfo);
+ }
+
+ /**
+ * request task error log
+ */
+ @RequestMapping(value = "/errlog", method = RequestMethod.POST)
+ public RResult taskErrlog(@RequestBody TaskLogReq taskInfo) {
+ return serverAgent.taskErrlog(taskInfo);
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java
new file mode 100644
index 0000000..7a542c7
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/controller/ServerController.java
@@ -0,0 +1,90 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.controller;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.AgentCommon;
+import org.apache.doris.manager.server.model.req.SshInfo;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("/server")
+public class ServerController {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerController.class);
+
+ @Autowired
+ private ServerProcess serverProcess;
+
+ /**
+ * install and start agent
+ */
+ @RequestMapping(value = "/installAgent", method = RequestMethod.POST)
+ public RResult installAgent(@RequestBody SshInfo sshInfo) {
+ serverProcess.initAgent(sshInfo);
+ serverProcess.startAgent(sshInfo);
+ return RResult.success();
+ }
+
+ /**
+ * agent info list
+ */
+ @RequestMapping(value = "/agentList", method = RequestMethod.POST)
+ public RResult agentList() {
+ return RResult.success(serverProcess.agentList());
+ }
+
+ /**
+ * agent role info
+ */
+ @RequestMapping(value = "/agentRole", method = RequestMethod.POST)
+ public RResult agentRole(@RequestBody Map<String, Object> params) {
+ Preconditions.checkArgument(params.containsKey("host"), "host can not empty");
+ String host = params.get("host").toString();
+ return RResult.success(serverProcess.agentRole(host));
+ }
+
+ /**
+ * heatbeat report api
+ */
+ @RequestMapping(value = "/heartbeat", method = RequestMethod.POST)
+ public RResult heartbeat(@RequestBody AgentCommon agent) {
+ log.info("{} heartbeat.", agent.getHost());
+ serverProcess.heartbeat(agent.getHost(), agent.getPort());
+ return RResult.success();
+ }
+
+ /**
+ * register report api
+ */
+ @RequestMapping(value = "/register", method = RequestMethod.POST)
+ public RResult register(@RequestBody AgentCommon agent) {
+ log.info("{} register.", agent.getHost());
+ return serverProcess.register(agent.getHost(), agent.getPort());
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java
new file mode 100644
index 0000000..38e9de9
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/ServerDao.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.dao;
+
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+
+import java.util.List;
+
+/**
+ * server dao
+ **/
+public interface ServerDao {
+
+ List<AgentEntity> queryAgentNodes(List<String> hosts);
+
+ AgentEntity agentInfo(String host, Integer port);
+
+ int refreshAgentStatus(String host, Integer port);
+
+ int registerAgent(String host, Integer port);
+
+ int updateBatchAgentStatus(List<AgentEntity> agents);
+
+ int insertAgentRole(List<AgentRoleEntity> agentRoles);
+
+ String agentRole(String host);
+
+ List<AgentRoleEntity> agentRoles();
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java
new file mode 100644
index 0000000..c916eb1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/dao/impl/ServerDaoImpl.java
@@ -0,0 +1,160 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.dao.impl;
+
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * server dao
+ **/
+@Repository
+public class ServerDaoImpl implements ServerDao {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Override
+ public List<AgentEntity> queryAgentNodes(List<String> hosts) {
+ String sql = "select id,host,port,status,register_time,last_reported_time" +
+ " from t_agent ";
+ if (hosts != null && !hosts.isEmpty()) {
+ sql = sql + " where host in (%s)";
+ String inSql = String.join(",", Collections.nCopies(hosts.size(), "?"));
+ sql = String.format(sql, inSql);
+ }
+ List<AgentEntity> agentEntities = jdbcTemplate.query(
+ sql, (resultSet, i) -> {
+ Integer id = resultSet.getInt("id");
+ String ht = resultSet.getString("host");
+ Integer pt = resultSet.getInt("port");
+ String status = resultSet.getString("status");
+ Date registerTime = resultSet.getTimestamp("register_time");
+ Date lastReportedTime = resultSet.getTimestamp("last_reported_time");
+ return new AgentEntity(id, ht, pt, status, registerTime, lastReportedTime);
+ }, hosts.toArray());
+ return agentEntities;
+ }
+
+ @Override
+ public AgentEntity agentInfo(String host, Integer port) {
+ String sql = "select id,host,port,status,register_time,last_reported_time from t_agent where host = ? and port = ?";
+ List<AgentEntity> agents = jdbcTemplate.query(sql, (resultSet, i) -> {
+ Integer id = resultSet.getInt("id");
+ String ht = resultSet.getString("host");
+ Integer pt = resultSet.getInt("port");
+ String status = resultSet.getString("status");
+ Date registerTime = resultSet.getTimestamp("register_time");
+ Date lastReportedTime = resultSet.getTimestamp("last_reported_time");
+ return new AgentEntity(id, ht, pt, status, registerTime, lastReportedTime);
+ }, host, port);
+ if (agents != null && !agents.isEmpty()) {
+ return agents.get(0);
+ }
+ return null;
+ }
+
+ @Override
+ public int refreshAgentStatus(String host, Integer port) {
+ String sql = "update t_agent set last_reported_time = now(),status = ? where host = ? and port = ?";
+ return jdbcTemplate.update(sql, AgentStatus.RUNNING.name(), host, port);
+ }
+
+ @Override
+ public int registerAgent(String host, Integer port) {
+ String sql = "insert into t_agent(host,port,status,register_time) values(?,?,?,now())";
+ return jdbcTemplate.update(sql, host, port, AgentStatus.RUNNING.name());
+ }
+
+ @Override
+ public int updateBatchAgentStatus(List<AgentEntity> agents) {
+ String sql = "update t_agent set status = ? where id = ?";
+ int[] i = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+ public void setValues(PreparedStatement ps, int i) throws SQLException {
+ AgentEntity agent = agents.get(i);
+ ps.setString(1, agent.getStatus());
+ ps.setInt(2, agent.getId());
+ }
+
+ public int getBatchSize() {
+ return agents.size();
+ }
+ });
+ return i.length;
+ }
+
+ @Override
+ public int insertAgentRole(List<AgentRoleEntity> agentRoles) {
+ String sql = "insert into t_agent_role(host,role,install_dir) values(?,?,?)";
+ int[] i = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+ public void setValues(PreparedStatement ps, int i) throws SQLException {
+ AgentRoleEntity node = agentRoles.get(i);
+ ps.setString(1, node.getHost());
+ ps.setString(2, node.getRole());
+ ps.setString(3, node.getInstallDir());
+ }
+
+ public int getBatchSize() {
+ return agentRoles.size();
+ }
+ });
+ return i.length;
+ }
+
+ @Override
+ public String agentRole(String host) {
+ String sql = "select host,role,install_dir from t_agent_role where host = ?";
+ List<AgentRoleEntity> agentRoles = jdbcTemplate.query(sql, (resultSet, i) -> {
+ String ht = resultSet.getString("host");
+ String role = resultSet.getString("role");
+ String installDir = resultSet.getString("install_dir");
+ return new AgentRoleEntity(ht, role, installDir);
+ }, host);
+ if (agentRoles != null && !agentRoles.isEmpty()) {
+ return agentRoles.get(0).getRole();
+ }
+ return null;
+ }
+
+ @Override
+ public List<AgentRoleEntity> agentRoles() {
+ String sql = "select host,role,install_dir from t_agent_role";
+ List<AgentRoleEntity> agentRoles = jdbcTemplate.query(sql, (resultSet, i) -> {
+ String ht = resultSet.getString("host");
+ String role = resultSet.getString("role");
+ String installDir = resultSet.getString("install_dir");
+ return new AgentRoleEntity(ht, role, installDir);
+ });
+ if (agentRoles == null) {
+ return new ArrayList<>();
+ }
+ return agentRoles;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java
new file mode 100644
index 0000000..1e7c86a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentEntity.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.entity;
+
+import java.util.Date;
+
+/**
+ * agent entity
+ **/
+public class AgentEntity {
+
+ private Integer id;
+
+ private String host;
+
+ private Integer port;
+
+ private String status;
+
+ private Date registerTime;
+
+ private Date lastReportedTime;
+
+ public AgentEntity() {
+ }
+
+ public AgentEntity(Integer id, String host, Integer port, String status, Date registerTime, Date lastReportedTime) {
+ this.id = id;
+ this.host = host;
+ this.port = port;
+ this.status = status;
+ this.registerTime = registerTime;
+ this.lastReportedTime = lastReportedTime;
+ }
+
+ public AgentEntity(String host, Integer port, String status) {
+ this.host = host;
+ this.port = port;
+ this.status = status;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public Date getRegisterTime() {
+ return registerTime;
+ }
+
+ public void setRegisterTime(Date registerTime) {
+ this.registerTime = registerTime;
+ }
+
+ public Date getLastReportedTime() {
+ return lastReportedTime;
+ }
+
+ public void setLastReportedTime(Date lastReportedTime) {
+ this.lastReportedTime = lastReportedTime;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java
new file mode 100644
index 0000000..fd0c82c
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/entity/AgentRoleEntity.java
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.entity;
+
+public class AgentRoleEntity {
+
+ private String host;
+
+ private String role;
+
+ private String installDir;
+
+ public AgentRoleEntity() {
+ }
+
+ public AgentRoleEntity(String host, String role,String installDir) {
+ this.host = host;
+ this.role = role;
+ this.installDir = installDir;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java
new file mode 100644
index 0000000..3a2657a
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/GlobalExceptionHandler.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.exceptions;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ @ExceptionHandler(ServerException.class)
+ public RResult handleException(ServerException exception) {
+ log.error(exception.getMessage(), exception);
+ return RResult.error(exception.getStatus(), exception.getMessage());
+ }
+
+ @ExceptionHandler(Throwable.class)
+ public RResult javaExceptionHandler(Exception ex) {
+ log.error("server error ", ex);
+ return RResult.error(5000, "server error");
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java
new file mode 100644
index 0000000..fa84864
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/exceptions/ServerException.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.exceptions;
+
+public class ServerException extends RuntimeException {
+ private static final long serialVersionUID = -1L;
+ private static final Integer DEAFULT_EXCEPTION_STATUS = 500;
+ private int status;
+
+
+ public ServerException(String message) {
+ this(message, DEAFULT_EXCEPTION_STATUS);
+ }
+
+ public ServerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ServerException(String message, int status) {
+ super(message);
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java
new file mode 100644
index 0000000..b5942f2
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/AgentCommon.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class AgentCommon {
+
+ private String host;
+
+ private Integer port;
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java
new file mode 100644
index 0000000..15cbd85
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExec.java
@@ -0,0 +1,50 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class DorisExec {
+
+ private String host;
+ //FE、BE
+ private String role;
+
+ private boolean master;
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public boolean isMaster() {
+ return master;
+ }
+
+ public void setMaster(boolean master) {
+ this.master = master;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java
new file mode 100644
index 0000000..1d08ba3
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisExecReq.java
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class DorisExecReq {
+
+ //START STOP RESTART
+ private String command;
+
+ private List<DorisExec> dorisExecs;
+
+ public String getCommand() {
+ return command;
+ }
+
+ public void setCommand(String command) {
+ this.command = command;
+ }
+
+ public List<DorisExec> getDorisExecs() {
+ return dorisExecs;
+ }
+
+ public void setDorisExecs(List<DorisExec> dorisExecs) {
+ this.dorisExecs = dorisExecs;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java
new file mode 100644
index 0000000..fcf0167
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/DorisInstallReq.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class DorisInstallReq {
+
+ private List<InstallInfo> installInfos;
+
+ public List<InstallInfo> getInstallInfos() {
+ return installInfos;
+ }
+
+ public void setInstallInfos(List<InstallInfo> installInfos) {
+ this.installInfos = installInfos;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java
new file mode 100644
index 0000000..4ea611f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/InstallInfo.java
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class InstallInfo {
+ //host
+ private String host;
+
+ //role be fe
+ private String role;
+
+ //package url
+ private String packageUrl;
+
+ private boolean mkFeMetadir;
+
+ private boolean mkBeStorageDir;
+
+ private String installDir;
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getPackageUrl() {
+ return packageUrl;
+ }
+
+ public void setPackageUrl(String packageUrl) {
+ this.packageUrl = packageUrl;
+ }
+
+ public boolean isMkFeMetadir() {
+ return mkFeMetadir;
+ }
+
+ public void setMkFeMetadir(boolean mkFeMetadir) {
+ this.mkFeMetadir = mkFeMetadir;
+ }
+
+ public String getInstallDir() {
+ return installDir;
+ }
+
+ public void setInstallDir(String installDir) {
+ this.installDir = installDir;
+ }
+
+ public boolean isMkBeStorageDir() {
+ return mkBeStorageDir;
+ }
+
+ public void setMkBeStorageDir(boolean mkBeStorageDir) {
+ this.mkBeStorageDir = mkBeStorageDir;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java
new file mode 100644
index 0000000..8c805c1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/SshInfo.java
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+import java.util.List;
+
+public class SshInfo {
+
+ private List<String> hosts;
+
+ private String user;
+
+ private Integer sshPort;
+
+ private String sshKey;
+
+ public List<String> getHosts() {
+ return hosts;
+ }
+
+ public void setHosts(List<String> hosts) {
+ this.hosts = hosts;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public Integer getSshPort() {
+ return sshPort;
+ }
+
+ public void setSshPort(Integer sshPort) {
+ this.sshPort = sshPort;
+ }
+
+ public String getSshKey() {
+ return sshKey;
+ }
+
+ public void setSshKey(String sshKey) {
+ this.sshKey = sshKey;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java
new file mode 100644
index 0000000..ca31b11
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskInfoReq.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class TaskInfoReq {
+
+ private String host;
+
+ private String taskId;
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getTaskId() {
+ return taskId;
+ }
+
+ public void setTaskId(String taskId) {
+ this.taskId = taskId;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java
new file mode 100644
index 0000000..91b63e6
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/model/req/TaskLogReq.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.model.req;
+
+public class TaskLogReq extends TaskInfoReq{
+ private int offset;
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java
new file mode 100644
index 0000000..3ba41c6
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerAgent.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+
+import java.util.List;
+
+
+/**
+ * server agent
+ **/
+public interface ServerAgent {
+
+ /**
+ * install doris
+ */
+ List<Object> install(DorisInstallReq installReq);
+
+ /**
+ * request agent rest api
+ */
+ List<Object> execute(DorisExecReq dorisExec);
+
+ /**
+ * fetch task info
+ */
+ RResult taskInfo(TaskInfoReq taskInfo);
+
+ /**
+ * fetch log
+ */
+ RResult taskStdlog(TaskLogReq taskInfo);
+
+ RResult taskErrlog(TaskLogReq taskInfo);
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java
new file mode 100644
index 0000000..e8fc9b1
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/ServerProcess.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.model.req.SshInfo;
+
+import java.util.List;
+
+/**
+ * server
+ */
+public interface ServerProcess {
+
+
+ void initAgent(SshInfo sshInfo);
+
+ /**
+ * install agent
+ */
+ void startAgent(SshInfo sshInfo);
+
+ /**
+ * agent list
+ */
+ List<AgentEntity> agentList();
+
+ /**
+ * update agent status batch
+ */
+ int updateBatchAgentStatus(List<AgentEntity> agents);
+
+ String agentRole(String host);
+
+ void heartbeat(String host, Integer port);
+
+ RResult register(String host, Integer port);
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java
new file mode 100644
index 0000000..515547e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerAgentImpl.java
@@ -0,0 +1,180 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.doris.manager.common.domain.BeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.CommandRequest;
+import org.apache.doris.manager.common.domain.CommandType;
+import org.apache.doris.manager.common.domain.FeInstallCommandRequestBody;
+import org.apache.doris.manager.common.domain.FeStartCommandRequestBody;
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.common.domain.Role;
+import org.apache.doris.manager.server.agent.AgentCache;
+import org.apache.doris.manager.server.agent.AgentRest;
+import org.apache.doris.manager.server.constants.CmdTypeEnum;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.entity.AgentRoleEntity;
+import org.apache.doris.manager.server.exceptions.ServerException;
+import org.apache.doris.manager.server.model.req.DorisExec;
+import org.apache.doris.manager.server.model.req.DorisExecReq;
+import org.apache.doris.manager.server.model.req.DorisInstallReq;
+import org.apache.doris.manager.server.model.req.InstallInfo;
+import org.apache.doris.manager.server.model.req.TaskInfoReq;
+import org.apache.doris.manager.server.model.req.TaskLogReq;
+import org.apache.doris.manager.server.service.ServerAgent;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+/**
+ * server agent
+ **/
+@Service
+public class ServerAgentImpl implements ServerAgent {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerAgentImpl.class);
+
+ @Autowired
+ private ServerDao serverDao;
+
+ @Autowired
+ private AgentRest agentRest;
+
+ @Autowired
+ private AgentCache agentCache;
+
+ @Override
+ public List<Object> install(DorisInstallReq installReq) {
+ List<String> agentRoleList = serverDao.agentRoles().stream()
+ .map(m -> (m.getHost() + "-" + m.getRole()))
+ .collect(Collectors.toList());
+ List<Object> results = new ArrayList<>();
+ List<InstallInfo> installInfos = installReq.getInstallInfos();
+ List<AgentRoleEntity> agentRoles = new ArrayList<>();
+ for (InstallInfo install : installInfos) {
+ String key = install.getHost() + "-" + install.getRole();
+ if (agentRoleList.contains(key)) {
+ log.warn("agent {} already install doris {}", install.getHost(), install.getRole());
+ continue;
+ }
+ RResult result = installDoris(install);
+ agentRoles.add(new AgentRoleEntity(install.getHost(), install.getRole(), install.getInstallDir()));
+ results.add(result.getData());
+ }
+ //save agent role
+ serverDao.insertAgentRole(agentRoles);
+ return results;
+ }
+
+ private RResult installDoris(InstallInfo install) {
+ CommandRequest creq = new CommandRequest();
+ if (Role.FE.name().equals(install.getRole())) {
+ FeInstallCommandRequestBody feBody = new FeInstallCommandRequestBody();
+ feBody.setMkFeMetadir(install.isMkFeMetadir());
+ feBody.setPackageUrl(install.getPackageUrl());
+ feBody.setInstallDir(install.getInstallDir());
+ creq.setCommandType(CommandType.INSTALL_FE.name());
+ creq.setBody(JSON.toJSONString(feBody));
+ } else if (Role.BE.name().equals(install.getRole())) {
+ BeInstallCommandRequestBody beBody = new BeInstallCommandRequestBody();
+ beBody.setMkBeStorageDir(install.isMkBeStorageDir());
+ beBody.setInstallDir(install.getInstallDir());
+ beBody.setPackageUrl(install.getPackageUrl());
+ creq.setCommandType(CommandType.INSTALL_BE.name());
+ }
+ RResult result = agentRest.commandExec(install.getHost(), agentPort(install.getHost()), creq);
+ return result;
+ }
+
+ @Override
+ public List<Object> execute(DorisExecReq dorisExec) {
+ List<Object> results = new ArrayList<>();
+ CmdTypeEnum cmdType = CmdTypeEnum.findByName(dorisExec.getCommand());
+ List<DorisExec> dorisExecs = dorisExec.getDorisExecs();
+ for (DorisExec exec : dorisExecs) {
+ CommandType commandType = transAgentCmd(cmdType, Role.findByName(exec.getRole()));
+ CommandRequest creq = new CommandRequest();
+ if (CommandType.START_FE.equals(commandType) && exec.isMaster()) {
+ FeStartCommandRequestBody feBody = new FeStartCommandRequestBody();
+ feBody.setHelper(true);
+ // request fe master ip and port
+ feBody.setHelpHostPort("");
+ }
+ creq.setCommandType(commandType.name());
+ RResult result = agentRest.commandExec(exec.getHost(), agentPort(exec.getHost()), creq);
+ Object data = result.getData();
+ results.add(data);
+ }
+ return results;
+ }
+
+ /**
+ * trans server command to agent command
+ */
+ public CommandType transAgentCmd(CmdTypeEnum cmdType, Role role) {
+ Preconditions.checkNotNull(cmdType, "unrecognized cmd type " + cmdType);
+ Preconditions.checkNotNull(role, "unrecognized role " + role);
+ String cmd = cmdType.name() + "_" + role.name();
+ return CommandType.findByName(cmd);
+ }
+
+ @Override
+ public RResult taskInfo(TaskInfoReq taskInfo) {
+ Map<String, Object> param = new HashMap<>();
+ param.put("taskId", taskInfo.getTaskId());
+ RResult result = agentRest.taskInfo(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+ return result;
+ }
+
+ @Override
+ public RResult taskStdlog(TaskLogReq taskInfo) {
+ Map<String, Object> param = new HashMap<>();
+ param.put("taskId", taskInfo.getTaskId());
+ param.put("offset", taskInfo.getOffset());
+ RResult result = agentRest.taskStdLog(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+ return result;
+ }
+
+ @Override
+ public RResult taskErrlog(TaskLogReq taskInfo) {
+ Map<String, Object> param = new HashMap<>();
+ param.put("taskId", taskInfo.getTaskId());
+ param.put("offset", taskInfo.getOffset());
+ RResult result = agentRest.taskErrLog(taskInfo.getHost(), agentPort(taskInfo.getHost()), param);
+ return result;
+ }
+
+ private Integer agentPort(String host) {
+ AgentEntity agent = agentCache.agentInfo(host);
+ if (agent == null) {
+ throw new ServerException("query agent port fail");
+ }
+ return agent.getPort();
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java
new file mode 100644
index 0000000..a2ea855
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/service/impl/ServerProcessImpl.java
@@ -0,0 +1,204 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.service.impl;
+
+import org.apache.doris.manager.common.domain.RResult;
+import org.apache.doris.manager.server.agent.AgentCache;
+import org.apache.doris.manager.server.constants.AgentStatus;
+import org.apache.doris.manager.server.dao.ServerDao;
+import org.apache.doris.manager.server.entity.AgentEntity;
+import org.apache.doris.manager.server.exceptions.ServerException;
+import org.apache.doris.manager.server.model.req.SshInfo;
+import org.apache.doris.manager.server.service.ServerProcess;
+import org.apache.doris.manager.server.shell.SCP;
+import org.apache.doris.manager.server.shell.SSH;
+import org.apache.doris.manager.server.util.Preconditions;
+import org.apache.doris.manager.server.util.PropertiesUtil;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.doris.manager.server.constants.Constants.KEY_DORIS_AGENT_INSTALL_DIR;
+import static org.apache.doris.manager.server.constants.Constants.KEY_DORIS_AGENT_START_SCRIPT;
+import static org.apache.doris.manager.server.constants.Constants.KEY_SERVER_PORT;
+
+/**
+ * server
+ **/
+@Service
+public class ServerProcessImpl implements ServerProcess {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerProcessImpl.class);
+ private static final String AGENT_INSTALL_DIR = PropertiesUtil.getPropValue(KEY_DORIS_AGENT_INSTALL_DIR);
+ private static final String AGENT_START_SCRIPT = PropertiesUtil.getPropValue(KEY_DORIS_AGENT_START_SCRIPT);
+
+ @Autowired
+ private ServerDao serverDao;
+
+ @Autowired
+ private AgentCache agentCache;
+
+ @Override
+ public void initAgent(SshInfo sshInfo) {
+ ApplicationHome applicationHome = new ApplicationHome(ServerProcessImpl.class);
+ String dorisManagerHome = applicationHome.getSource().getParentFile().getParentFile().toString();
+ log.info("doris manager home : {}", dorisManagerHome);
+ String agentHome = dorisManagerHome + File.separator + "agent";
+ Preconditions.checkNotNull(sshInfo.getHosts(), "hosts is empty");
+ File sshKeyFile = buildSshKeyFile();
+ writeSshKeyFile(sshInfo.getSshKey(), sshKeyFile);
+ scpFile(sshInfo, agentHome, AGENT_INSTALL_DIR);
+ }
+
+ @Override
+ public void startAgent(SshInfo sshInfo) {
+ String command = "sh " + AGENT_INSTALL_DIR + File.separator + AGENT_START_SCRIPT + " --server " + getServerAddr() + " --agent %s";
+ List<String> hosts = sshInfo.getHosts();
+ for (String host : hosts) {
+ File sshKeyFile = buildSshKeyFile();
+ String cmd = String.format(command, host);
+ SSH ssh = new SSH(sshInfo.getUser(), sshInfo.getSshPort(),
+ sshKeyFile.getAbsolutePath(), host, cmd);
+ Integer run = ssh.run();
+ if (run != 0) {
+ throw new ServerException("agent start failed");
+ } else {
+ log.info("agent start success");
+ }
+ }
+ }
+
+ @Override
+ public List<AgentEntity> agentList() {
+ List<AgentEntity> agentEntities = serverDao.queryAgentNodes(new ArrayList<>());
+ return agentEntities;
+ }
+
+ @Override
+ public int updateBatchAgentStatus(List<AgentEntity> agents) {
+ return serverDao.updateBatchAgentStatus(agents);
+ }
+
+ @Override
+ public String agentRole(String host) {
+ return serverDao.agentRole(host);
+ }
+
+ @Override
+ public void heartbeat(String host, Integer port) {
+ serverDao.refreshAgentStatus(host, port);
+ }
+
+ @Override
+ public RResult register(String host, Integer port) {
+ AgentEntity agentEntity = serverDao.agentInfo(host, port);
+ if (agentEntity != null) {
+ return RResult.success("agent already register");
+ }
+ serverDao.registerAgent(host, port);
+ agentCache.putAgent(new AgentEntity(host, port, AgentStatus.RUNNING.name()));
+ return RResult.success("agent register success");
+ }
+
+ /**
+ * scp agent package
+ */
+ private void scpFile(SshInfo sshDesc, String localPath, String remotePath) {
+ List<String> hosts = sshDesc.getHosts();
+ String checkFileExistCmd = "if test -e " + remotePath + "; then echo ok; else mkdir -p " + remotePath + " ;fi";
+ File sshKeyFile = buildSshKeyFile();
+ for (String host : hosts) {
+ //check remote dir exist
+ SSH ssh = new SSH(sshDesc.getUser(), sshDesc.getSshPort(),
+ sshKeyFile.getAbsolutePath(), host, checkFileExistCmd);
+ if (ssh.run() != 0) {
+ throw new ServerException("scp create remote dir failed");
+ }
+ SCP scp = new SCP(sshDesc.getUser(), sshDesc.getSshPort(),
+ sshKeyFile.getAbsolutePath(), host, localPath, remotePath);
+ Integer run = scp.run();
+ if (run != 0) {
+ log.error("scp agent package failed:{} to {}", localPath, remotePath);
+ throw new ServerException("scp agent package failed");
+ }
+ }
+ }
+
+ /**
+ * sshkey trans to file
+ */
+ private void writeSshKeyFile(String sshKey, File sshKeyFile) {
+ try {
+ if (sshKeyFile.exists()) {
+ sshKeyFile.delete();
+ }
+ FileUtils.writeStringToFile(sshKeyFile, sshKey, Charset.defaultCharset());
+ } catch (IOException e) {
+ log.error("build sshKey file failed:", e);
+ throw new ServerException("build sshKey file failed");
+ }
+ }
+
+ /**
+ * build sshkeyfile per request
+ */
+ private File buildSshKeyFile() {
+ File sshKeyFile = new File("conf", "sshkey");
+
+ // chmod ssh key file permission to 600
+ try {
+ Set<PosixFilePermission> permission = new HashSet<>();
+ permission.add(PosixFilePermission.OWNER_READ);
+ permission.add(PosixFilePermission.OWNER_WRITE);
+ Files.setPosixFilePermissions(Paths.get(sshKeyFile.getAbsolutePath()), permission);
+ } catch (IOException e) {
+ log.error("set ssh key file permission fail");
+ }
+ return sshKeyFile;
+ }
+
+ /**
+ * get server address
+ */
+ private String getServerAddr() {
+ String host = null;
+ try {
+ host = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ throw new ServerException("get server ip fail");
+ }
+ String port = PropertiesUtil.getPropValue(KEY_SERVER_PORT);
+ return host + ":" + port;
+ }
+
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java
new file mode 100644
index 0000000..53d15d9
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/BaseCommand.java
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.stream.Collectors;
+
+/**
+ * base command
+ **/
+public abstract class BaseCommand {
+
+ private static final Logger log = LoggerFactory.getLogger(BaseCommand.class);
+
+ protected String[] resultCommand;
+ protected Long timeout = 10000L;
+
+ protected abstract void buildCommand();
+
+ public Integer run() {
+ buildCommand();
+ log.info("run command: {}", StringUtils.join(resultCommand, " "));
+ ProcessBuilder pb = new ProcessBuilder(resultCommand);
+ int exitCode = 1;
+ try {
+ Process process = pb.start();
+ if (waitForProcessTermination(process, timeout)) {
+ exitCode = process.exitValue();
+ } else {
+ process.destroy();
+ }
+ if (exitCode != 0) {
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String errorStream = bufferedReader.lines().parallel().collect(Collectors.joining(System.lineSeparator()));
+ log.info("shell command error response:{}", errorStream);
+ }
+ } catch (IOException ie) {
+ log.error("command execute fail", ie);
+ }
+ return exitCode;
+ }
+
+ /**
+ * Waits until the process has terminated or waiting time elapses.
+ *
+ * @param timeout time to wait in miliseconds
+ * @return true if process has exited, false otherwise
+ */
+ protected boolean waitForProcessTermination(Process process, long timeout) {
+ long startTime = System.currentTimeMillis();
+ do {
+ try {
+ process.exitValue();
+ return true;
+ } catch (IllegalThreadStateException ignored) {
+ }
+ // Check if process has terminated once per second
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ } while (System.currentTimeMillis() - startTime < timeout);
+ return false;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java
new file mode 100644
index 0000000..815746e
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SCP.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+/**
+ * scp
+ **/
+public class SCP extends BaseCommand {
+
+ private String user;
+ private Integer sshPort;
+ private String sshKeyFile;
+ private String host;
+ private String localPath;
+ private String remotePath;
+
+ public SCP(String user, Integer sshPort, String sshKeyFile, String host, String localPath, String remotePath) {
+ this.user = user;
+ this.sshPort = sshPort;
+ this.sshKeyFile = sshKeyFile;
+ this.host = host;
+ this.localPath = localPath;
+ this.remotePath = remotePath;
+ }
+
+ @Override
+ protected void buildCommand() {
+ String[] command = new String[]{"scp",
+ "-r",
+ "-o", "ConnectTimeOut=60",
+ "-o", "StrictHostKeyChecking=no",
+ "-o", "BatchMode=yes",
+ "-P", this.sshPort.toString(),
+ "-i", this.sshKeyFile,
+ this.localPath,
+ this.user + "@" + this.host + ":" + this.remotePath
+ };
+ this.resultCommand = command;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java
new file mode 100644
index 0000000..e132c91
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/shell/SSH.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.shell;
+
+/**
+ * ssh
+ **/
+public class SSH extends BaseCommand {
+
+ private String user;
+
+ private Integer sshPort;
+
+ private String sshKeyFile;
+
+ private String host;
+
+ private String command;
+
+ public SSH(String user, Integer sshPort, String sshKeyFile, String host, String command) {
+ this.user = user;
+ this.sshPort = sshPort;
+ this.sshKeyFile = sshKeyFile;
+ this.host = host;
+ this.command = command;
+ }
+
+ protected void buildCommand() {
+ String[] command = new String[]{"ssh",
+ "-o", "ConnectTimeOut=60",
+ "-o", "StrictHostKeyChecking=no",
+ "-o", "BatchMode=yes",
+ "-tt",
+ "-i", this.sshKeyFile,
+ "-p", this.sshPort.toString(),
+ this.user + "@" + this.host, this.command
+ };
+ this.resultCommand = command;
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java
new file mode 100644
index 0000000..c45ae9f
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/Preconditions.java
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.util;
+
+public class Preconditions {
+
+ public static <T> T checkNotNull(T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+
+ public static <T> T checkNotNull(T reference, String errorMessage) {
+ if (reference == null) {
+ throw new NullPointerException(String.valueOf(errorMessage));
+ }
+ return reference;
+ }
+
+ public static void checkArgument(boolean condition) {
+ if (!condition) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public static void checkArgument(boolean condition, Object errorMessage) {
+ if (!condition) {
+ throw new IllegalArgumentException(String.valueOf(errorMessage));
+ }
+ }
+}
diff --git a/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java
new file mode 100644
index 0000000..2dd1741
--- /dev/null
+++ b/manager/dm-server/src/main/java/org/apache/doris/manager/server/util/PropertiesUtil.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.doris.manager.server.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Properties;
+
+public class PropertiesUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
+ private static final String DEFAULT_PROPERTIES = "/application.properties";
+
+ /**
+ * get properties key
+ *
+ * @param propKey
+ * @return
+ */
+ public static String getPropValue(String propKey) {
+ try {
+ Properties props = new Properties();
+ InputStream inputStream = PropertiesUtil.class.getResourceAsStream(DEFAULT_PROPERTIES);
+ BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+ props.load(bf);
+ return props.getProperty(propKey);
+ } catch (IOException e) {
+ log.error("get propKey error:", e);
+ }
+ return null;
+ }
+}
diff --git a/manager/dm-server/src/main/resources/application.properties b/manager/dm-server/src/main/resources/application.properties
new file mode 100644
index 0000000..a34d7cc
--- /dev/null
+++ b/manager/dm-server/src/main/resources/application.properties
@@ -0,0 +1,15 @@
+server.port=9601
+
+spring.datasource.url = jdbc:mysql://localhost:3306/doris_manager?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+spring.datasource.username = root
+spring.datasource.password = password
+
+doris.manager.agent.install.dir = /usr/local/doris-manager
+doris.manager.agent.start-script = agent/bin/agent_start.sh
+
+
+
+
+
+
+
diff --git a/manager/dm-server/src/main/resources/bin/startup.sh b/manager/dm-server/src/main/resources/bin/startup.sh
new file mode 100755
index 0000000..0967ee2
--- /dev/null
+++ b/manager/dm-server/src/main/resources/bin/startup.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export DOIRS_MANAGER_HOME=`cd "$curdir/.."; pwd`
+
+#
+# JAVA_OPTS
+# SERVER_PARAMS
+# LOG_DIR
+# PID_DIR
+export JAVA_OPTS="-Xmx1024m"
+export LOG_DIR="$DOIRS_MANAGER_HOME/log"
+export PID_DIR=`cd "$curdir"; pwd`
+
+# java
+if [ "$JAVA_HOME" = "" ]; then
+ echo "Error: JAVA_HOME is not set."
+ exit 1
+fi
+JAVA=$JAVA_HOME/bin/java
+
+# need check and create if the log directory existed before outing message to the log file.
+if [ ! -d $LOG_DIR ]; then
+ mkdir -p $LOG_DIR
+fi
+
+echo $JAVA_OPTS >> $LOG_DIR/doris-manager.out
+
+pidfile=$PID_DIR/doris-manager.pid
+
+if [ -f $pidfile ]; then
+ if kill -0 `cat $pidfile` > /dev/null 2>&1; then
+ echo doris-manager running as process `cat $pidfile`. Stop it first.
+ exit 1
+ fi
+fi
+
+echo `date` >> $LOG_DIR/doris-manager.out
+
+nohup $JAVA $JAVA_OPTS -jar ${DOIRS_MANAGER_HOME}/lib/dm-server.jar $SERVER_PARAMS >> $LOG_DIR/doris-manager.out 2>&1 </dev/null &
+
+echo $! > $pidfile
diff --git a/manager/dm-server/src/main/resources/bin/stop.sh b/manager/dm-server/src/main/resources/bin/stop.sh
new file mode 100755
index 0000000..6f15bba
--- /dev/null
+++ b/manager/dm-server/src/main/resources/bin/stop.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+curdir=`dirname "$0"`
+curdir=`cd "$curdir"; pwd`
+
+export DORIS_MANAGER_HOME=`cd "$curdir/.."; pwd`
+export PID_DIR=`cd "$curdir"; pwd`
+
+pidfile=$PID_DIR/doris-manager.pid
+
+if [ -f $pidfile ]; then
+ pid=`cat $pidfile`
+ pidcomm=`ps -p $pid -o comm=`
+
+ if [ "java" != "$pidcomm" ]; then
+ echo "ERROR: pid process may not be doris manager. "
+ fi
+
+ if kill -9 $pid > /dev/null 2>&1; then
+ echo "stop $pidcomm, and remove pid file. "
+ rm $pidfile
+ fi
+fi
diff --git a/manager/dm-server/src/main/resources/dm-server.sql b/manager/dm-server/src/main/resources/dm-server.sql
new file mode 100644
index 0000000..f9af9e7
--- /dev/null
+++ b/manager/dm-server/src/main/resources/dm-server.sql
@@ -0,0 +1,18 @@
+CREATE TABLE `t_agent` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `host` varchar(128) DEFAULT NULL COMMENT 'agent host',
+ `port` int(8) DEFAULT NULL COMMENT 'agent port',
+ `status` varchar(256) DEFAULT NULL COMMENT 'agent status',
+ `register_time` timestamp NULL COMMENT 'register_time',
+ `last_reported_time` timestamp NULL COMMENT 'last report time'
+ PRIMARY KEY (`id`)
+ UNIQUE KEY `agent_index` (`host`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+
+CREATE TABLE `t_agent_role` (
+ `host` varchar(128) DEFAULT NULL COMMENT 'host',
+ `role` varchar(8) DEFAULT NULL COMMENT 'BE/FE',
+ `install_dir` varchar(256) DEFAULT NULL COMMENT 'doris install dir',
+ UNIQUE KEY `host_index` (`host`,`role`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/manager/dm-server/src/main/resources/logback-spring.xml b/manager/dm-server/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..e437501
--- /dev/null
+++ b/manager/dm-server/src/main/resources/logback-spring.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false">
+ <springProperty scope="context" name="springAppName" source="spring.application.name" defaultValue="server" />
+ <property name="LOG_HOME" value="./log"/>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+ </encoder>
+ </appender>
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+ <FileNamePattern>${LOG_HOME}/${springAppName}.%d{yyyy-MM-dd}.%i.log</FileNamePattern>
+ <MaxHistory>30</MaxHistory>
+ <maxFileSize>50MB</maxFileSize>
+ <totalSizeCap>10GB</totalSizeCap>
+ </rollingPolicy>
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="INFO">
+ <appender-ref ref="STDOUT" />
+ <appender-ref ref="FILE" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git "a/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md" "b/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..aeccad3
--- /dev/null
+++ "b/manager/doc/Doris Manager Server \346\216\245\345\217\243\346\226\207\346\241\243.md"
@@ -0,0 +1,486 @@
+[TOC]
+
+---
+
+### Doris Manager Server 接口文档
+
+#### 1.安装Agent
+
+**接口功能**
+
+> 给指定机器安装Agent,并启动。
+
+**URL**
+
+> /server/installAgent
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |hosts |ture |List|机器列表 |
+> |user |true |String |ssh 用户|
+> |port |true |int |ssh 端口|
+> |sshKey |true |String |ssh 私钥|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+|:----- |:------|:----------------------------- |
+|msg |String |调用信息 |
+|code |String | 结果状态。0:正常 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/server/installAgent
+
+> 请求参数:
+``` json
+{
+ "hosts":["10.10.10.11"],
+ "user":"root",
+ "sshPort":22,
+ "sshKey": "-----BEGIN RSA PRIVATE KEY-----....."
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0
+}
+```
+
+#### 2.查看Agent列表
+
+**接口功能**
+
+> 查看已安装的Agent列表
+
+**URL**
+
+> /server/agentList
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+无
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+|:----- |:------|:----------------------------- |
+|msg |String |调用信息 |
+|code |String | 结果状态。0:正常 |
+|data.id |int | agentId |
+|data.host |String |agent host |
+|data.port |String | agent port |
+|data.status |String | agent状态 :RUNNING STOP|
+|data.registerTime |Date | agent注册时间 |
+|data.lastReportedTime |Date | agent最后上报时间 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/server/agentList
+
+> 请求参数:无
+
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": [
+ {
+ "id": 1,
+ "host": "10.10.10.11",
+ "port": 9602,
+ "status": "RUNNING",
+ "registerTime": "2021-08-10T11:07:34.000+00:00",
+ "lastReportedTime": "2021-08-12T03:02:46.000+00:00"
+ }
+ ]
+}
+```
+
+#### 3.安装Doris
+
+**接口功能**
+
+> 给指定机器安装Doris
+
+**URL**
+
+> /agent/installDoris
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |host |ture | String |指定安装doris的机器 |
+> |role |true |String |doris角色:FE、BE|
+> |packageUrl |true |String |doris编译包下载地址,只支持http方式。|
+> |mkFeMetadir |false |boolean |安装FE时是否新建 元数据目录|
+> |mkBeStorageDir |false |boolean |安装BE时是否新建 数据存储目录|
+> |installDir |true |String |安装路径|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+> |:----- |:------|:----------------------------- |
+> |msg |String |调用信息 |
+> |code |String | 结果状态。0:正常 |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间 |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/installDoris
+
+> 请求参数:
+``` json
+{
+ "installInfos":[{
+ "host":"10.10.10.11",
+ "role":"FE",
+ "packageUrl":"http://10.10.10.11/fileupload/doris-fe.tar.gz",
+ "mkFeMetadir":true,
+ "installDir":"/usr/local/doris-fe"
+ }]
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": [
+ {
+ "taskResult": {
+ "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+ "submitTime": "2021-08-12T02:37:11.757+00:00",
+ "startTime": "2021-08-12T02:37:11.759+00:00",
+ "endTime": null,
+ "taskState": "RUNNING",
+ "retCode": null
+ },
+ "stdlogs": [],
+ "errlogs": []
+ }
+ ]
+}
+```
+
+#### 4.启停Doris
+
+**接口功能**
+
+> 对指定机器的doris进行启动、停止
+
+**URL**
+
+> /agent/execute
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |command |ture | String | 执行命令: START STOP |
+> |dorisExecs.host |true |String |指定的机器列表|
+> |dorisExecs.role |true |String |doris角色:FE、BE|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+> |:----- |:------|:----------------------------- |
+> |msg |String |调用信息 |
+> |code |String | 结果状态。0:正常 |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间 |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/execute
+
+> 请求参数:
+``` json
+{
+ "command":"START",
+ "dorisExecs":[{
+ "host":"10.10.10.11",
+ "role":"FE"
+ }]
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": [
+ {
+ "taskResult": {
+ "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+ "submitTime": "2021-08-12T02:37:11.757+00:00",
+ "startTime": "2021-08-12T02:37:11.759+00:00",
+ "endTime": null,
+ "taskState": "RUNNING",
+ "retCode": null
+ },
+ "stdlogs": [],
+ "errlogs": []
+ }
+ ]
+}
+```
+
+#### 5.查看任务执行状态
+
+**接口功能**
+
+> 查看任务执行状态
+
+**URL**
+
+> /agent/task
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |host |ture | String |agent 机器host |
+> |taskId |true |String |任务id|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+> |:----- |:------|:----------------------------- |
+> |msg |String |调用信息 |
+> |code |String | 结果状态。0:正常 |
+> |data.taskResult.taskId |String | 任务ID |
+> |data.taskResult.submitTime |Date | 任务提交时间 |
+> |data.taskResult.startTime |Date | 任务开始时间 |
+> |data.taskResult.endTime |Date | 任务终止时间 |
+> |data.taskResult.taskState |String | 任务状态 |
+> |data.taskResult.retCode |int | 任务返回状态。0:正常 |
+> |data.stdlogs |List | 任务输出日志 |
+> |data.errlogs |List | 任务错误日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/task
+
+> 请求参数:
+``` json
+{
+ "host":"10.10.10.11",
+ "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26"
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": {
+ "taskResult": {
+ "taskId": "a3b966cc10794f4c8b9b2c0dc1fa9b26",
+ "submitTime": "2021-08-12T02:37:11.757+00:00",
+ "startTime": "2021-08-12T02:37:11.759+00:00",
+ "endTime": "2021-08-12T02:37:14.759+00:00",
+ "taskState": "FINISHED",
+ "retCode": 0
+ },
+ "stdlogs": [
+ "bin/",
+ "bin/start_fe.sh",
+ "bin/stop_fe.sh",
+ "conf/",
+ "conf/fe.conf",
+ "lib/",
+ "lib/RoaringBitmap-0.8.13.jar",
+ "lib/activation-1.1.1.jar",
+ "lib/aircompressor-0.10.jar",
+ "lib/amqp-client-5.7.3.jar",
+ "lib/annotations-2.15.45.jar"
+ .....
+ ],
+ "errlogs": []
+ }
+}
+```
+
+#### 6.查看任务输出日志
+
+**接口功能**
+
+> 查看任务输出日志
+
+**URL**
+
+> /agent/stdlog
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |host |ture | String |agent 机器host |
+> |taskId |true |String |任务id|
+> |offset |false |int |日志偏移量|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+> |:----- |:------|:----------------------------- |
+> |msg |String |调用信息 |
+> |code |String | 结果状态。0:正常 |
+> |data.key |String | 下一页起始偏移量 |
+> |data.value |List | 日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/stdlog
+
+> 请求参数:
+``` json
+{
+ "host":"10.10.10.11",
+ "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26",
+ "offset":10,
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": {
+ "key": 366,
+ "value": [
+ "lib/annotations-2.15.45.jar",
+ "lib/antlr4-runtime-4.7.jar",
+ .....
+ ]
+ }
+}
+```
+
+#### 7.查看任务错误日志
+
+**接口功能**
+
+> 查看任务错误日志
+
+**URL**
+
+> /agent/errlog
+
+**支持格式**
+
+> JSON
+
+**HTTP请求方式**
+
+> POST
+
+**请求参数**
+
+> |参数|必选|类型|说明|
+> |:----- |:-------|:-----|----- |
+> |host |ture | String |agent 机器host |
+> |taskId |true |String |任务id|
+> |offset |false |int |日志偏移量|
+
+**返回字段**
+
+> |返回字段|字段类型|说明 |
+> |:----- |:------|:----------------------------- |
+> |msg |String |调用信息 |
+> |code |String | 结果状态。0:正常 |
+> |data.key |String | 下一页起始偏移量 |
+> |data.value |List | 日志 |
+
+**接口示例**
+
+> 地址:http://localhost:9601/agent/errlog
+
+> 请求参数:
+``` json
+{
+ "host":"10.10.10.11",
+ "taskId":"a3b966cc10794f4c8b9b2c0dc1fa9b26",
+ "offset":10,
+}
+```
+> 返回参数:
+``` json
+{
+ "msg": "success",
+ "code": 0,
+ "data": {
+ "key": 366,
+ "value": [
+ .....
+ ]
+ }
+}
+```
\ No newline at end of file
diff --git a/manager/pom.xml b/manager/pom.xml
new file mode 100644
index 0000000..a5eb07e
--- /dev/null
+++ b/manager/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>2.5.2</version>
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+
+ <groupId>org.apache.doris</groupId>
+ <artifactId>doris-manager</artifactId>
+ <version>1.0.0</version>
+ <packaging>pom</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-common</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-agent</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.doris</groupId>
+ <artifactId>dm-server</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <modules>
+ <module>dm-common</module>
+ <module>dm-agent</module>
+ <module>dm-server</module>
+ <module>assembly</module>
+ </modules>
+
+</project>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org