搜索
首页Javajava教程Java 如何与 Ansible 自动运维平台对接?

Java对接ansible自动运维化平台实现文件采集分发

此次对接主要为以下两个功能:

  • 文件采集(对文件进行批量操作,包括批量从多台主机中采集共性文件如日志文件)

  • 文件分发(对文件进行批量操作,包括批量从多台主机中分发共性文件如日志文件)

场景说明及ansible yum安装

因ansible没有Windows的安装包,所以为了方便测试,搭建了一套Linux环境进行后续工作。

此次采用yum方式安装,在采用yum方式安装Ansible,首先安装EPEL源。

yum install -y http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

查看EPEL源中的Ansible版本

yum info ansible

直接安装此版本,如果有其他要求,请调整源,安装其他ansible版本

yum install -y ansible

安装完成之后,查看ansible版本信息

ansible --version

配置Ansible服务器清单

清单文件/etc/ansible/hosts,在此文件中编写节点主机的对应IP地址和端口

Java 如何与 Ansible 自动运维平台对接?

我这里只是做一个演示,其中IP后面可以添加节点真实的SSH的端口,在定义的内容上面有一个[]列表,里面的内容为自定义内容,方面为了操作绑定的节点主机,我习惯称之为分组列表

简单的认证一下,Ping一下添加的主机

Java 如何与 Ansible 自动运维平台对接?

成功安装ansible !!

Java代码实现文件分发

顾名思义,文件分发就是把本机的文件分发到多个主机。

这时候就需要 Apache POI(大家可以去导入对应的包)来创建本机的文件了(ansible Host配置文件也通过POI创建)

POI创建文件工具类

package com.tiduyun.cmp.operation.utils;

import com.tiduyun.cmp.common.model.operation.HostInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author huyuan@tiduyun.com ansible创建文件
 */
@Slf4j
@Component
public class AnsibleCreateFileUtils {
    private final static String filename = "hosts";

    public static String passWordConnect(List<HostInfo> hostInfo, String hostGroup , String directory) throws IOException{
        /** 在本地新建一个文件夹 里面创建一个文件 向里面写入内容 */


        // 创建文件夹对象 创建文件对象
        File folder = new File(directory);
        // 如果文件夹不存在 就创建一个空的文件夹
        if (!folder.exists()) {
            log.info("创建了文件夹{}" , folder);
            folder.mkdirs();
        }
        File file = new File(directory, filename);
        // 如果文件不存在 就创建一个空的文件
        if (!file.exists()) {
            try {
                log.info("创建了文件{}" , file);
                file.createNewFile();
            } catch (IOException e) {
                log.error("error data{}" , e);
            }
        }
        // 写入数据
        // 创建文件字节输出流
        FileOutputStream fos = new FileOutputStream(file);
        try {
            List<String> list = new ArrayList<>();
            for (HostInfo data : hostInfo) {
                // 开始写
                String string = data.getHost() + " ansible_ssh_pass=" + data.getPasswd() + " ansible_ssh_user="
                    + data.getAccount() + " ansible_ssh_port=" + data.getPort();
                list.add(string);
            }
            String splicingData = StringUtils.join(list, "\n");
            String str = "[" + hostGroup + "]" + "\n" + splicingData;
            byte[] bytes = str.getBytes();
            // 将byte数组中的所有数据全部写入
            fos.write(bytes);
            fos.flush();
            log.info("文件内容{}" , str);
            // 删除文件
            // deleteFile(file);
            // 关闭流

        } catch (IOException e) {
            log.error("error data{}" , e);
            throw e;
        }finally {
            if (fos != null) {
                fos.close();
            }
        }
        return directory;
    }

    public static void deleteFile(File file) {
        if (file.exists()) {// 判断路径是否存在
            if (file.isFile()) {// boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。
                file.delete();
            } else {// 不是文件,对于文件夹的操作
                    // 保存 路径D:/1/新建文件夹2 下的所有的文件和文件夹到listFiles数组中
                File[] listFiles = file.listFiles();// listFiles方法:返回file路径下所有文件和文件夹的绝对路径
                for (File file2 : listFiles) {
                    /*
                     * 递归作用:由外到内先一层一层删除里面的文件 再从最内层 反过来删除文件夹
                     *    注意:此时的文件夹在上一步的操作之后,里面的文件内容已全部删除
                     *         所以每一层的文件夹都是空的  ==》最后就可以直接删除了
                     */
                    deleteFile(file2);
                }
            }
            file.delete();
        } else {
            log.error("该file路径不存在!!");
        }

    }
}

创建主机组配置文件

:ansible分为两种连接方式,这里采用的是密钥连接,生成的文件已拼接密钥!!!后续的采集与分发都要用到这个。(如有不懂的小伙伴,可以去查找一下ansible的连接方式)

    @Override
    public void ansibleCreateHost(HostInfo hostInfo, String Key) {
        ParamCheckUtils.notNull(hostInfo, "hostInfo");

        List<HostInfo> HostIp = Arrays.asList(hostInfo);
        for (HostInfo data : HostIp) {
            String ansiblePassWd = data.getPasswd();
            String PassWd = hostInfoService.decode(ansiblePassWd);
            data.setPasswd(PassWd);
        }
        try {
            AnsibleCreateFileUtils.passWordConnect(HostIp, ansibleConfigurationItemVo.getHostGroup(),
                ansibleConfigurationItemVo.getDirectory());
        } catch (IOException e) {
            log.error("Failed to create host configuration{}", e);
        }
    }

实现文件分发

主机配置文件已经配置好,接下来就是执行ansible对应的命令,通过Java拼接ansible命令。

执行命令工具类

<br>
package com.tiduyun.cmp.operation.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import static cn.hutool.db.DbUtil.close;

/**
 * @author huyuan@tiduyun.com ansible执行命令工具类
 * upload 上传文件
 * createRemoteDirectory  创建远程目录
 */
@Slf4j
public class AnsibleExecuteTheOrderUtils {

    private final static String commandBin = "/bin/sh";

    private final static String commandC = "-c";


    /**
     *  创建远程目录
     */
    public static void createRemoteDirectory(String hostGroup, String remotePath, String directory) throws IOException {
        Runtime run = Runtime.getRuntime();
        String[] cmds = new String[3];
        cmds[0] = commandBin;
        cmds[1] = commandC;
        cmds[2] =
                "ansible " + hostGroup + " -m command -a " + "\"mkdir " + remotePath + "\"" + " -i " + directory + "/hosts";

        // 执行CMD命令
        Process p = run.exec(cmds);
        log.info("ansible远程执行命令为{}", cmds[2]);

        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
        try {
            String lineMes;
            while ((lineMes = br.readLine()) != null)
                log.info(lineMes);// 打印输出信息
            try {
                // 检查命令是否执行失败。
                if (p.waitFor() != 0) {
                    if (p.exitValue() == 1)// 0表示正常结束,1:非正常结束
                        log.error("命令执行失败");
                }
            } catch (InterruptedException e) {
                log.error("error data{}", e);
            }
        } catch (IOException e) {
            log.error("fail to carry out command{}", e);
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }

    }

    /**
     *  文件分发
     */
    public static void upload(String hostGroup, String localPath, String remotePath, String directory)
        throws IOException {
        Runtime run = Runtime.getRuntime();
        String[] cmds = new String[3];
        cmds[0] = commandBin;
        cmds[1] = commandC;
        cmds[2] = "ansible " + hostGroup + " -m copy -a " + "\"src=" + localPath + " dest=" + remotePath + "\"" + " -i "
            + directory + "/hosts";
        // 执行CMD命令
        Process p = run.exec(cmds);
        log.info("ansible命令为{}", cmds[2]);

        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
        try {
            String lineMes;
            while ((lineMes = br.readLine()) != null)
                log.info("ansible输出信息为 :" + lineMes);// 打印输出信息
            try {
                // 检查命令是否执行失败。
                if (p.waitFor() != 0) {
                    if (p.exitValue() == 1)// 0表示正常结束,1:非正常结束
                        log.error("命令执行失败");
                }
            } catch (InterruptedException e) {
                log.error("error data{}", e);
            }
        } catch (IOException e) {
            log.error("fail to carry out command{}", e);
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }

    }

    /**
     *  文件采集
     */
    public static void fileCollection(String hostGroup, String remotePath, String localPath , String directory) throws IOException {
        Runtime run = Runtime.getRuntime();
        String[] cmds = new String[3];
        cmds[0] = commandBin;
        cmds[1] = commandC;
        cmds[2] = "ansible " + hostGroup + " -m fetch -a " + "\"src=" + remotePath + " dest=" + localPath + " force=yes backup=yes\"" + " -i "
                + directory + "/hosts";

        // 执行CMD命令
        Process p = run.exec(cmds);
        log.info("ansible远程采集文件命令为{}", cmds[2]);

        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
        try {
            String lineMes;
            while ((lineMes = br.readLine()) != null)
                log.info(lineMes);// 打印输出信息
            try {
                // 检查命令是否执行失败。
                if (p.waitFor() != 0) {
                    if (p.exitValue() == 1)// 0表示正常结束,1:非正常结束
                        log.error("命令执行失败");
                }
            } catch (InterruptedException e) {
                log.error("error data{}", e);
            }
        } catch (IOException e) {
            log.error("fail to carry out command{}", e);
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }

    }

    public static void ExecuteTheOrder(String command) throws IOException {
        log.info("start execute cmd {}", command);

        String[] cmd = new String[] {"/bin/bash", "-c", command};
        Runtime run = Runtime.getRuntime();
        Process p = run.exec(cmd); // 执行CMD命令

        BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("UTF-8")));
        try {
            String lineMes;
            while ((lineMes = br.readLine()) != null)
                log.info("输出信息为 {}", lineMes);// 打印输出信息
            try {
                // 检查命令是否执行失败。
                if (p.waitFor() != 0) {
                    if (p.exitValue() == 1)// 0表示正常结束,1:非正常结束
                        log.error("命令执行失败");
                }
            } catch (InterruptedException e) {
                log.error("error data{}", e);
            }

        } catch (IOException e) {
            log.error("fail to carry out command{}", e);
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }
    }

    public static void disconnect() {
        try {
            close();
        } catch (Exception ex) {
            // Ignore because disconnection is quietly
        }
    }

    // public void execute(String command) throws Exception {
    // log.info("start execute cmd {}", command);
    // try (Session session = sshClient.startSession()) {
    // Session.Command exec = session.exec(command);
    //
    // Integer readLineCount = 0;
    // InputStream in = exec.getInputStream();
    // log.info(IOUtils.readFully(in).toString());
    // String errorMessage = IOUtils.readFully(exec.getErrorStream(), LoggerFactory.DEFAULT).toString();
    // log.info(errorMessage);
    // if (exec.getExitStatus() != null && exec.getExitStatus() != 0) {
    // throw new RuntimeException(
    // "exec " + command + " error,error message is " + errorMessage + ",error code " + exec.getExitStatus());
    // }
    // log.info("exec result code {}", exec.getExitStatus());
    //
    // }
    //
    // }
}

接下来就是调用

package com.tiduyun.cmp.operation.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.tiduyun.cmp.common.model.flow.UploadFile;
import com.tiduyun.cmp.common.model.operation.ComponentInfo;
import com.tiduyun.cmp.common.model.operation.HostInfo;
import com.tiduyun.cmp.common.provider.service.ExceptionBuildService;
import com.tiduyun.cmp.operation.constant.OperationExceptionCode;
import com.tiduyun.cmp.operation.constant.StartCmdSeparate;
import com.tiduyun.cmp.operation.model.AnsibleConfigurationItemVo;
import com.tiduyun.cmp.operation.model.vo.FileQueryVo;
import com.tiduyun.cmp.operation.service.AnsibleTaskRecordService;
import com.tiduyun.cmp.operation.service.ComposerDeployService;
import com.tiduyun.cmp.operation.service.HostInfoService;
import com.tiduyun.cmp.operation.service.UploadFileService;
import com.tiduyun.cmp.operation.utils.AnsibleExecuteTheOrderUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class AnsibleDeployServiceImpl implements ComposerDeployService {

    @Value(value = "${cmp.operation.commandHeader:cmd /c}")
    private String commandHeader;

    @Value(value = "${cmp.operation.filePath:/data/cmp/file}")
    private String filePath;

    @Value(value = "${cmp.operation.remoteFilePath:/tmp}")
    private String remoteFilePath;

    @Autowired
    private AnsibleTaskRecordService ansibleTaskRecordService;

    @Autowired
    private AnsibleConfigurationItemVo ansibleConfigurationItemVo;

    @Autowired
    private UploadFileService uploadFileService;

    @Autowired
    private HostInfoService hostInfoService;

    @Autowired
    private ExceptionBuildService exceptionBuildService;

    @Override
    public void deploy(HostInfo hostInfo, ComponentInfo componentInfo, String cpmposerName) {
        ansibleTaskRecordService.ansibleCreateHost(hostInfo, null);

        try {
            String remotePath = StringUtils.join(remoteFilePath, "/", cpmposerName, "-", componentInfo.getName(), "-",
                RandomUtil.randomString(3));
            log.info("remote file path = {}", remotePath);

            List<Integer> fileIds = getFileIds(componentInfo.getFileUrl());
            if (CollectionUtils.isNotEmpty(fileIds)) {
                FileQueryVo uploadFileQueryVo = new FileQueryVo();
                uploadFileQueryVo.setIds(fileIds);
                List<UploadFile> uploadFiles = uploadFileService.query(uploadFileQueryVo);
                for (UploadFile uploadFile : uploadFiles) {
                    String path = StringUtils.join(filePath, uploadFile.getFilePath());
                    File file = new File(path);
                    if (!file.exists()) {
                        log.error("file url is {}", file.getPath());
                        throw exceptionBuildService.buildException(OperationExceptionCode.FILE_NOT_EXIST,
                            new Object[] {uploadFile.getFileName()});
                    }
                    // 创建远程目录
                    AnsibleExecuteTheOrderUtils.createRemoteDirectory(ansibleConfigurationItemVo.getHostGroup(),
                        StringUtils.join(remotePath), ansibleConfigurationItemVo.getDirectory());

                    // 分发文件
                    AnsibleExecuteTheOrderUtils.upload(ansibleConfigurationItemVo.getHostGroup(), path,
                        StringUtils.join(remotePath, "/", uploadFile.getFileName()),
                        ansibleConfigurationItemVo.getDirectory());
                }
            }
            List<String> startCmds = getStartCmds(componentInfo.getStartCmd());
            if (CollectionUtils.isNotEmpty(startCmds)) {
                String cdCmd = StringUtils.join("cd ", remotePath);
                String execCmd = StringUtils.join(startCmds, ";");
                execCmd = StringUtils.join(cdCmd, ";", execCmd);
                log.info("execCmd= " + execCmd);
                // sshClient.execute(execCmd);
                AnsibleExecuteTheOrderUtils.ExecuteTheOrder(execCmd);

            } else {
                log.error("parse startCmd fail {}", componentInfo.getStartCmd());
            }

        } catch (Exception e) {
            log.error("主机[{}]部署[{}]组件失败,主机ID[{}],组件ID[{}]:", hostInfo.getHost(), componentInfo.getName(),
                hostInfo.getId(), componentInfo.getId(), e);
            throw exceptionBuildService.buildException(OperationExceptionCode.EXECUTE_CMD_ERROR,
                new Object[] {e.getMessage()});

        } finally {
            AnsibleExecuteTheOrderUtils.disconnect();
        }

    }

    @Override
    public boolean isSupport(HostInfo hostInfo) {
        return true;
    }

    private List<Integer> getFileIds(String fileIds) {
        List<Integer> ids = new ArrayList<>();
        if (fileIds == null) {
            return null;
        }
        String[] split = StringUtils.split(fileIds, ",");
        for (String s : split) {
            ids.add(Integer.parseInt(s));
        }
        return ids;
    }

    private List<String> getStartCmds(String startCmd) {
        List<String> cmd = new ArrayList<>();
        if (startCmd == null) {
            return cmd;
        }
        String[] split = StrUtil.split(startCmd, StartCmdSeparate.SIGN);
        cmd.addAll(Arrays.asList(split));
        return cmd;

    }

    public static Boolean needCd(String s) {
        String[] splits = StrUtil.split(s, "&&");
        int maxIndex = splits.length - 1;
        String cmd = splits[maxIndex];
        if (StrUtil.startWith(cmd, "cd")) {
            return false;
        } else {
            return true;
        }

    }
}

文件采集

同上,调用两个工具类

@Override
    public void fileCollection(HostInfo hostInfo, String remotePath, String localPath) {
        ansibleCreateHost(hostInfo, null);
        try {
            log.info("remote file path = {}", remotePath);
            log.info("local file path = {}", localPath);

            // 文件采集
            AnsibleExecuteTheOrderUtils.fileCollection(ansibleConfigurationItemVo.getHostGroup(), remotePath,
                localPath , ansibleConfigurationItemVo.getDirectory());
        } catch (Exception e) {
            log.error("主机[{}]文件采集失败,主机ID[{}]:", hostInfo.getHost(), hostInfo.getId(), e);
            throw exceptionBuildService.buildException(OperationExceptionCode.EXECUTE_CMD_ERROR,
                new Object[] {e.getMessage()});

        } finally {
            AnsibleExecuteTheOrderUtils.disconnect();
        }

    }

以上是Java 如何与 Ansible 自动运维平台对接?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:亿速云。如有侵权,请联系admin@php.cn删除
如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?Mar 17, 2025 pm 05:46 PM

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?Mar 17, 2025 pm 05:44 PM

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?Mar 17, 2025 pm 05:43 PM

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Mar 17, 2025 pm 05:35 PM

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境