This is an automated email from the ASF dual-hosted git repository.

wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new 7d3c388d BIGTOP-4287: Support Agent remotely installed by Server (#112)
7d3c388d is described below

commit 7d3c388d62a9cc4930b2eb3538cadb477407d411
Author: Zhiguo Wu <[email protected]>
AuthorDate: Thu Nov 28 09:59:08 2024 +0800

    BIGTOP-4287: Support Agent remotely installed by Server (#112)
---
 .../src/main/resources/assembly/agent.xml          |   6 +-
 .../manager/server/controller/HostController.java  |   7 ++
 .../manager/server/enums/ApiExceptionEnum.java     |   3 +-
 .../bigtop/manager/server/enums/LocaleKeys.java    |   1 +
 .../manager/server/model/req/HostPathReq.java      |  34 ++++++
 .../bigtop/manager/server/service/HostService.java |   9 ++
 .../server/service/impl/HostServiceImpl.java       | 116 ++++++++++++++++++---
 .../src/main/resources/assembly/server.xml         |   6 +-
 .../src/main/resources/ddl/MySQL-DDL-CREATE.sql    |   2 +-
 .../main/resources/ddl/PostgreSQL-DDL-CREATE.sql   |   2 +-
 .../main/resources/i18n/messages_en_US.properties  |   1 +
 .../main/resources/i18n/messages_zh_CN.properties  |   1 +
 dev-support/docker/containers/build.sh             |   6 +-
 13 files changed, 166 insertions(+), 28 deletions(-)

diff --git a/bigtop-manager-agent/src/main/resources/assembly/agent.xml 
b/bigtop-manager-agent/src/main/resources/assembly/agent.xml
index a8d51bb9..e464a927 100644
--- a/bigtop-manager-agent/src/main/resources/assembly/agent.xml
+++ b/bigtop-manager-agent/src/main/resources/assembly/agent.xml
@@ -22,10 +22,10 @@
           xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 
http://maven.apache.org/xsd/assembly-2.1.0.xsd";>
     <id>agent</id>
     <formats>
-        <format>dir</format>
+        <format>tar.gz</format>
     </formats>
-    <includeBaseDirectory>false</includeBaseDirectory>
-    <baseDirectory>agent</baseDirectory>
+    <includeBaseDirectory>true</includeBaseDirectory>
+    <baseDirectory>bigtop-manager-agent</baseDirectory>
     <fileSets>
         <fileSet>
             <directory>${basedir}/src/main/resources</directory>
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/HostController.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/HostController.java
index 5f6890eb..b8fdafcf 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/HostController.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/HostController.java
@@ -21,6 +21,7 @@ package org.apache.bigtop.manager.server.controller;
 import org.apache.bigtop.manager.dao.query.HostQuery;
 import org.apache.bigtop.manager.server.model.converter.HostConverter;
 import org.apache.bigtop.manager.server.model.dto.HostDTO;
+import org.apache.bigtop.manager.server.model.req.HostPathReq;
 import org.apache.bigtop.manager.server.model.req.HostReq;
 import org.apache.bigtop.manager.server.model.vo.HostVO;
 import org.apache.bigtop.manager.server.model.vo.PageVO;
@@ -103,4 +104,10 @@ public class HostController {
         HostDTO hostDTO = HostConverter.INSTANCE.fromReq2DTO(hostReq);
         return ResponseEntity.success(hostService.checkConnection(hostDTO));
     }
+
+    @Operation(summary = "Install dependencies", description = "Install 
dependencies on a host")
+    @PostMapping("/install-dependencies")
+    public ResponseEntity<Boolean> checkConnection(@RequestBody @Validated 
HostPathReq hostPathReq) {
+        return 
ResponseEntity.success(hostService.installDependencies(hostPathReq.getHostIds(),
 hostPathReq.getPath()));
+    }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
index 2613fc47..26d432bb 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
@@ -39,7 +39,8 @@ public enum ApiExceptionEnum {
     HOST_ASSIGNED(12001, LocaleKeys.HOST_ASSIGNED),
     HOST_NOT_CONNECTED(12002, LocaleKeys.HOST_NOT_CONNECTED),
     HOST_UNABLE_TO_CONNECT(12003, LocaleKeys.HOST_UNABLE_TO_CONNECT),
-    HOST_HAS_COMPONENTS(12004, LocaleKeys.HOST_HAS_COMPONENTS),
+    HOST_UNABLE_TO_EXEC_COMMAND(12004, LocaleKeys.HOST_UNABLE_TO_EXEC_COMMAND),
+    HOST_HAS_COMPONENTS(12005, LocaleKeys.HOST_HAS_COMPONENTS),
 
     // Stack Exceptions -- 13000 ~ 13999
     STACK_NOT_FOUND(13000, LocaleKeys.STACK_NOT_FOUND),
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/LocaleKeys.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/LocaleKeys.java
index 94314912..e42d177f 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/LocaleKeys.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/LocaleKeys.java
@@ -41,6 +41,7 @@ public enum LocaleKeys {
     HOST_ASSIGNED("host.assigned"),
     HOST_NOT_CONNECTED("host.not.connected"),
     HOST_UNABLE_TO_CONNECT("host.unable.to.connect"),
+    HOST_UNABLE_TO_EXEC_COMMAND("host.unable.to.exec.command"),
     HOST_HAS_COMPONENTS("host.has.components"),
 
     STACK_NOT_FOUND("stack.not.found"),
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/HostPathReq.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/HostPathReq.java
new file mode 100644
index 00000000..a3d39bd4
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/HostPathReq.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
+ *
+ *    https://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.bigtop.manager.server.model.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class HostPathReq {
+
+    @Schema(example = "[1, 2]")
+    private List<Long> hostIds;
+
+    @Schema(example = "/opt")
+    private String path;
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/HostService.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/HostService.java
index 4de47e85..210cae4b 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/HostService.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/HostService.java
@@ -71,4 +71,13 @@ public interface HostService {
      * @return true if all hosts are able to connect
      */
     Boolean checkConnection(HostDTO hostDTO);
+
+    /**
+     * Install dependencies
+     *
+     * @param hostIds host ids
+     * @param path remote host path
+     * @return true if all dependencies are installed
+     */
+    Boolean installDependencies(List<Long> hostIds, String path);
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/HostServiceImpl.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/HostServiceImpl.java
index 30de0974..bf8cdb06 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/HostServiceImpl.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/HostServiceImpl.java
@@ -18,11 +18,14 @@
  */
 package org.apache.bigtop.manager.server.service.impl;
 
+import org.apache.bigtop.manager.common.constants.MessageConstants;
 import org.apache.bigtop.manager.common.shell.ShellResult;
 import org.apache.bigtop.manager.dao.po.HostPO;
+import org.apache.bigtop.manager.dao.po.RepoPO;
 import org.apache.bigtop.manager.dao.query.HostQuery;
 import org.apache.bigtop.manager.dao.repository.ComponentDao;
 import org.apache.bigtop.manager.dao.repository.HostDao;
+import org.apache.bigtop.manager.dao.repository.RepoDao;
 import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.enums.HostAuthTypeEnum;
@@ -53,6 +56,9 @@ import java.util.stream.Collectors;
 @Service
 public class HostServiceImpl implements HostService {
 
+    @Resource
+    private RepoDao repoDao;
+
     @Resource
     private HostDao hostDao;
 
@@ -140,25 +146,9 @@ public class HostServiceImpl implements HostService {
     @Override
     public Boolean checkConnection(HostDTO hostDTO) {
         String command = "hostname";
-        HostAuthTypeEnum authType = 
HostAuthTypeEnum.fromCode(hostDTO.getAuthType());
         for (String hostname : hostDTO.getHostnames()) {
             try {
-                ShellResult result = null;
-                switch (authType) {
-                    case PASSWORD -> result = RemoteSSHUtils.executeCommand(
-                            hostname, hostDTO.getSshPort(), 
hostDTO.getSshUser(), hostDTO.getSshPassword(), command);
-                    case KEY -> result = RemoteSSHUtils.executeCommand(
-                            hostname,
-                            hostDTO.getSshPort(),
-                            hostDTO.getSshUser(),
-                            hostDTO.getSshKeyFilename(),
-                            hostDTO.getSshKeyString(),
-                            hostDTO.getSshKeyPassword(),
-                            command);
-                    case NO_AUTH -> result = RemoteSSHUtils.executeCommand(
-                            hostname, hostDTO.getSshPort(), 
hostDTO.getSshUser(), command);
-                }
-
+                ShellResult result = execCommandOnRemoteHost(hostDTO, 
hostname, command);
                 if (result.getExitCode() != 0) {
                     log.error("Unable to connect to host, hostname: {}, msg: 
{}", hostname, result.getErrMsg());
                     throw new 
ApiException(ApiExceptionEnum.HOST_UNABLE_TO_CONNECT, hostname);
@@ -173,4 +163,96 @@ public class HostServiceImpl implements HostService {
 
         return true;
     }
+
+    @Override
+    public Boolean installDependencies(List<Long> hostIds, String path) {
+        List<RepoPO> repoPOList = repoDao.findAll();
+        Map<String, RepoPO> archRepoMap = repoPOList.stream()
+                .filter(repoPO -> repoPO.getType() == 2)
+                .collect(Collectors.toMap(RepoPO::getArch, repo -> repo));
+
+        List<HostPO> hostPOList = hostDao.findByIds(hostIds);
+        for (HostPO hostPO : hostPOList) {
+            HostDTO hostDTO = HostConverter.INSTANCE.fromPO2DTO(hostPO);
+
+            // Get host arch
+            String arch = execCommandOnRemoteHost(hostDTO, 
hostDTO.getHostname(), "arch")
+                    .getOutput()
+                    .trim();
+            arch = arch.equals("arm64") ? "aarch64" : arch;
+
+            // Download & Extract agent tarball
+            String repoUrl = archRepoMap.get(arch).getBaseUrl();
+            String tarballUrl = repoUrl + "/bigtop-manager-agent.tar.gz";
+            String command = "curl -L " + tarballUrl + " | tar -xz -C " + path;
+            ShellResult result = execCommandOnRemoteHost(hostDTO, 
hostDTO.getHostname(), command);
+            if (result.getExitCode() != MessageConstants.SUCCESS_CODE) {
+                hostPO.setErrInfo(result.getErrMsg());
+                hostDao.updateById(hostPO);
+
+                log.error(
+                        "Unable to download & extract agent tarball, hostname: 
{}, msg: {}",
+                        hostDTO.getHostname(),
+                        result.getErrMsg());
+                throw new 
ApiException(ApiExceptionEnum.HOST_UNABLE_TO_EXEC_COMMAND, 
hostDTO.getHostname());
+            }
+
+            // Run agent in background
+            command = "nohup " + path + "/bigtop-manager-agent/bin/start.sh > 
/dev/null 2>&1 &";
+            result = execCommandOnRemoteHost(hostDTO, hostDTO.getHostname(), 
command);
+            if (result.getExitCode() != MessageConstants.SUCCESS_CODE) {
+                hostPO.setErrInfo(result.getErrMsg());
+                hostDao.updateById(hostPO);
+
+                log.error("Unable to start agent, hostname: {}, msg: {}", 
hostDTO.getHostname(), result.getErrMsg());
+                throw new 
ApiException(ApiExceptionEnum.HOST_UNABLE_TO_EXEC_COMMAND, 
hostDTO.getHostname());
+            }
+
+            // Check the process, the agent may encounter some errors and exit 
when starting
+            // So we need to wait for a while before the check
+            try {
+                Thread.sleep(10 * 1000);
+            } catch (InterruptedException e) {
+                log.error("Thread sleep interrupted", e);
+            }
+            command = "ps -ef | grep bigtop-manager-agent | grep -v grep";
+            result = execCommandOnRemoteHost(hostDTO, hostDTO.getHostname(), 
command);
+            if (result.getExitCode() != MessageConstants.SUCCESS_CODE
+                    || !result.getOutput().contains("bigtop-manager-agent")) {
+                hostPO.setErrInfo("Unable to start agent process, please check 
the log");
+                hostDao.updateById(hostPO);
+
+                log.error("Unable to start agent process, hostname: {}", 
hostDTO.getHostname());
+                throw new 
ApiException(ApiExceptionEnum.HOST_UNABLE_TO_EXEC_COMMAND, 
hostDTO.getHostname());
+            }
+
+            hostPO.setStatus(HealthyStatusEnum.HEALTHY.getCode());
+            hostDao.updateById(hostPO);
+        }
+
+        return true;
+    }
+
+    private ShellResult execCommandOnRemoteHost(HostDTO hostDTO, String 
hostname, String command) {
+        HostAuthTypeEnum authType = 
HostAuthTypeEnum.fromCode(hostDTO.getAuthType());
+        try {
+            return switch (authType) {
+                case PASSWORD -> RemoteSSHUtils.executeCommand(
+                        hostname, hostDTO.getSshPort(), hostDTO.getSshUser(), 
hostDTO.getSshPassword(), command);
+                case KEY -> RemoteSSHUtils.executeCommand(
+                        hostname,
+                        hostDTO.getSshPort(),
+                        hostDTO.getSshUser(),
+                        hostDTO.getSshKeyFilename(),
+                        hostDTO.getSshKeyString(),
+                        hostDTO.getSshKeyPassword(),
+                        command);
+                case NO_AUTH -> RemoteSSHUtils.executeCommand(
+                        hostname, hostDTO.getSshPort(), hostDTO.getSshUser(), 
command);
+            };
+        } catch (Exception e) {
+            log.error("Unable to exec command on host, hostname: {}, command: 
{}", hostname, command, e);
+            throw new 
ApiException(ApiExceptionEnum.HOST_UNABLE_TO_EXEC_COMMAND, hostname);
+        }
+    }
 }
diff --git a/bigtop-manager-server/src/main/resources/assembly/server.xml 
b/bigtop-manager-server/src/main/resources/assembly/server.xml
index c8f303f4..d8310722 100644
--- a/bigtop-manager-server/src/main/resources/assembly/server.xml
+++ b/bigtop-manager-server/src/main/resources/assembly/server.xml
@@ -22,10 +22,10 @@
           xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 
http://maven.apache.org/xsd/assembly-2.1.0.xsd";>
     <id>server</id>
     <formats>
-        <format>dir</format>
+        <format>tar.gz</format>
     </formats>
-    <includeBaseDirectory>false</includeBaseDirectory>
-    <baseDirectory>server</baseDirectory>
+    <includeBaseDirectory>true</includeBaseDirectory>
+    <baseDirectory>bigtop-manager-server</baseDirectory>
     <fileSets>
         <fileSet>
             <directory>${basedir}/src/main/resources</directory>
diff --git a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql 
b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
index db5dcbd7..761abea4 100644
--- a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
+++ b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
@@ -109,7 +109,7 @@ CREATE TABLE `host`
     `total_memory_size`    BIGINT,
     `desc`                 VARCHAR(255) DEFAULT NULL,
     `status`               INTEGER DEFAULT NULL COMMENT '1-healthy, 
2-unhealthy, 3-unknown',
-    `err_info`             VARCHAR(255) DEFAULT NULL,
+    `err_info`             TEXT DEFAULT NULL,
     `create_time`          DATETIME     DEFAULT CURRENT_TIMESTAMP,
     `update_time`          DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP,
     `create_by`            BIGINT,
diff --git 
a/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql 
b/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql
index 9cdff18d..060893b9 100644
--- a/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql
+++ b/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql
@@ -97,7 +97,7 @@ CREATE TABLE host
     total_memory_size    BIGINT,
     "desc"               VARCHAR(255)  DEFAULT NULL,
     status               INT  DEFAULT NULL,
-    err_info             VARCHAR(255)  DEFAULT NULL,
+    err_info             TEXT  DEFAULT NULL,
     create_time          TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP,
     update_time          TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP,
     create_by            BIGINT,
diff --git 
a/bigtop-manager-server/src/main/resources/i18n/messages_en_US.properties 
b/bigtop-manager-server/src/main/resources/i18n/messages_en_US.properties
index 03f44141..d18f087f 100644
--- a/bigtop-manager-server/src/main/resources/i18n/messages_en_US.properties
+++ b/bigtop-manager-server/src/main/resources/i18n/messages_en_US.properties
@@ -35,6 +35,7 @@ host.not.found=Host not exist
 host.assigned=Hosts [{0}] already assigned to another cluster
 host.not.connected=Hosts [{0}] not connected
 host.unable.to.connect=Unable to connect to host [{0}]
+host.unable.to.exec.command=Unable to execute command on host [{0}]
 host.has.components=Host still has components, please remove them first
 
 stack.not.found=Stack not exist
diff --git 
a/bigtop-manager-server/src/main/resources/i18n/messages_zh_CN.properties 
b/bigtop-manager-server/src/main/resources/i18n/messages_zh_CN.properties
index df922bb3..a12bbc2b 100644
--- a/bigtop-manager-server/src/main/resources/i18n/messages_zh_CN.properties
+++ b/bigtop-manager-server/src/main/resources/i18n/messages_zh_CN.properties
@@ -35,6 +35,7 @@ host.not.found=主机不存在
 host.assigned=主机 [{0}] 已属于其他集群
 host.not.connected=主机 [{0}] 未连接
 host.unable.to.connect=无法连接到主机 [{0}]
+host.unable.to.exec.command=无法在主机 [{0}] 上执行命令
 host.has.components=主机上仍有组件,请先移除
 
 stack.not.found=组件栈不存在
diff --git a/dev-support/docker/containers/build.sh 
b/dev-support/docker/containers/build.sh
index afe8090d..4fc0f4cc 100644
--- a/dev-support/docker/containers/build.sh
+++ b/dev-support/docker/containers/build.sh
@@ -67,12 +67,14 @@ create_container() {
     log "Create ${container_name}"
     if [ $i -eq 1 ]; then
       docker run -itd -p 15005:5005 -p 15006:5006 -p 18080:8080 --name 
${container_name} --hostname ${container_name} --network bigtop-manager 
--cap-add=SYS_TIME bigtop-manager/develop:${OS}
-      docker cp ../../../bigtop-manager-server/target/bigtop-manager-server 
${container_name}:/opt/
+      docker cp 
../../../bigtop-manager-server/target/bigtop-manager-server.tar.gz 
${container_name}:/opt/
+      docker exec ${container_name} bash -c "cd /opt && tar -zxvf 
bigtop-manager-server.tar.gz"
       SERVER_PUB_KEY=`docker exec ${container_name} /bin/cat 
/root/.ssh/id_rsa.pub`
     else
       docker run -itd --name ${container_name} --hostname ${container_name} 
--network bigtop-manager --cap-add=SYS_TIME bigtop-manager/develop:${OS}
     fi
-      docker cp ../../../bigtop-manager-agent/target/bigtop-manager-agent 
${container_name}:/opt/
+      docker cp 
../../../bigtop-manager-agent/target/bigtop-manager-agent.tar.gz 
${container_name}:/opt/
+      docker exec ${container_name} bash -c "cd /opt && tar -zxvf 
bigtop-manager-agent.tar.gz"
       docker exec ${container_name} bash -c "echo '$SERVER_PUB_KEY' > 
/root/.ssh/authorized_keys"
       docker exec ${container_name} ssh-keygen -N '' -t rsa -b 2048 -f 
/etc/ssh/ssh_host_rsa_key
       docker exec ${container_name} ssh-keygen -N '' -t ecdsa -b 256 -f 
/etc/ssh/ssh_host_ecdsa_key

Reply via email to