Heim  >  Artikel  >  Java  >  Wie verbindet sich Java mit der automatischen Betriebs- und Wartungsplattform Ansible?

Wie verbindet sich Java mit der automatischen Betriebs- und Wartungsplattform Ansible?

WBOY
WBOYnach vorne
2023-04-20 16:40:081273Durchsuche

Java stellt eine Verbindung zur Ansible-Plattform für automatischen Betrieb und Wartung her, um die Sammlung und Verteilung von Dateien zu realisieren

Diese Verbindung hat hauptsächlich die folgenden zwei Funktionen:

  • Dateisammlung (Batch-Vorgänge für Dateien, einschließlich Batch-Sammlung gemeinsamer Dateien aus mehreren Hosts) Wie Protokolldateien)

  • Dateiverteilung (Batch-Vorgänge für Dateien, einschließlich Batch-Verteilung allgemeiner Dateien wie Protokolldateien von mehreren Hosts)

Szenariobeschreibung und Ansible-Yum-Installation

Weil Ansible nicht vorhanden ist ein Windows-Installationspaket. Um das Testen zu erleichtern, wurde eine Linux-Umgebung für spätere Arbeiten erstellt.

Dieses Mal wird die yum-Methode zur Installation verwendet. Nachdem Sie Ansible mit der yum-Methode installiert haben, installieren Sie zunächst die EPEL-Quelle.

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

Sehen Sie sich die Ansible-Version in der EPEL-Quelle an

yum info ansible

Installieren Sie diese Version direkt. Bitte passen Sie die Quelle an und installieren Sie andere Ansible-Versionen.

Yum install -y ansible

Nach Abschluss der Installation überprüfen Sie die Ansible-Versionsinformationen. -Version

Konfigurieren Sie die Ansible-Serverliste

Inventardatei /etc/ansible/hosts, schreiben Sie die entsprechende IP-Adresse und den Port des Knotenhosts in diese Datei

Ich mache hier nur eine Demonstration, wo die reale Der SSH-Port des Knotens kann nach der IP hinzugefügt werden. Über dem definierten Inhalt befindet sich eine Liste, und der Inhalt darin ist benutzerdefinierter Inhalt. Um den gebundenen Knotenhost zu betreiben, bin ich es gewohnt, ihn als Gruppenliste zu bezeichnen. Authentifizieren Sie einfach den hinzugefügten Host und pingen Sie ihn an. Wie verbindet sich Java mit der automatischen Betriebs- und Wartungsplattform Ansible?

Ansible wurde erfolgreich installiert! !

Java-Code implementiert die Dateiverteilung

Wie der Name schon sagt, besteht die Dateiverteilung darin, lokale Dateien an mehrere Hosts zu verteilen.

Wie verbindet sich Java mit der automatischen Betriebs- und Wartungsplattform Ansible?Zu diesem Zeitpunkt benötigen Sie Apache POI (Sie können das entsprechende Paket importieren), um lokale Dateien zu erstellen (die ansible Host-Konfigurationsdatei wird ebenfalls über POI erstellt).

Hinweis

: Ansible ist in zwei Verbindungsmethoden unterteilt. Hier wird die Schlüsselverbindung verwendet, und die generierte Datei wurde mit dem Schlüssel gespleißt! ! ! Diese werden für die spätere Sammlung und Verteilung verwendet. (Wenn Sie Freunde haben, die es nicht verstehen, können Sie die Ansible-Verbindungsmethode nachschlagen.)

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路径不存在!!");
        }

    }
}

Dateiverteilung realisieren

Die Host-Konfigurationsdatei wurde konfiguriert. Der nächste Schritt besteht darin, den entsprechenden Befehl von Ansible auszuführen und zu verbinden Ansible-Befehl über Java.

Befehlswerkzeugklasse ausführen

    @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);
        }
    }
<br>

Der nächste Schritt besteht darin,

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());
    //
    // }
    //
    // }
}

Dateisammlung

Wie oben aufzurufen, zwei Werkzeugklassen aufzurufen

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;
        }

    }
}

Das obige ist der detaillierte Inhalt vonWie verbindet sich Java mit der automatischen Betriebs- und Wartungsplattform Ansible?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen