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

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

成功安装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的连接方式)

    @Overridepublic 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命令。

执行命令工具类

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;@Autowiredprivate AnsibleTaskRecordService ansibleTaskRecordService;@Autowiredprivate AnsibleConfigurationItemVo ansibleConfigurationItemVo;@Autowiredprivate UploadFileService uploadFileService;@Autowiredprivate HostInfoService hostInfoService;@Autowiredprivate ExceptionBuildService exceptionBuildService;@Overridepublic 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();}}@Overridepublic 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;}}
}

文件采集

同上,调用两个工具类

@Overridepublic 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自动运维化平台相关推荐

  1. 自动运维化tools篇1:用expect完成用户密码的批量修改

    用expect完成用户密码的批量修改 第三方工具expect,专门用来实现需要交互式操作的命令的自动无人工干预操作.这些命令常见的有:passwd.fsck.telnet.ftp等. 1.创建用户/密 ...

  2. 自动运维化tools篇2:通过SSH信任关系,批量修改LINUX密码

    通过SSH信任关系,批量修改LINUX密码    作者:IORI 原创 2007-2-28 15点 于CC 一 ============================================ ...

  3. Ansible自动化运维_超详细

    Ansible自动化运维 自动化运维工具简介 Puppet 自动运维工具特点: Saltstack 自动运维工具特点: Ansible 自动运维工具特点: Ansible 运维工具原理 Ansible ...

  4. Ansible自动化运维的安装及常用模块解释

    (一)前言: Ansible是今年来越来越火的一款开源运维自动化工具,通过Ansible可以实现运维自动化,提高运维工程师的工作效率,减少人为失误.Ansible通过本身集成的非常丰富的模块可以实现各 ...

  5. java开源运维平台_推荐一个:开源自动化运维开发平台(IT Automatic Develop Platform)...

    ELVES IT Automatic Develop Platform Elves为光宇游戏运维团队开源的一套自动化运维开发平台(IT Automatic Develop Platform),面向开发 ...

  6. java运维软件下载_开源运维自动化平台-opendevops

    开源运维自动化平台-opendevops 简介 CODO是一款为用户提供企业多混合云.自动化运维.完全开源的云管理平台. CODO前端基于Vue iview开发.为用户提供友好的操作界面,增强用户体验 ...

  7. 建设DevOps统一运维监控平台,全面的系统监控你做好了吗?

    本文转自微信号EAWorld.扫描下方二维码,关注成功后,回复"普元方法+",将会获得热门课堂免费学习机会! 前言 随着Devops.云计算.微服务.容器等理念的逐步落地和大力发展 ...

  8. 中小型运维团队如何设计运维自动化平台

    前言 我给中小型运维团队的定义是整个团队人数(所有运维工程师 + 运维开发工程师)为 20 人以下,一般这样的团队,能为自动化投入的资源也许就 1.2 个开发人员. BAT 等大公司的 DevOps ...

  9. 携程运维自动化平台,上万服务器变更也可以很轻松

    讲师简介 胡俊雅:携程资深技术支持工程师 个人简介:携程技术保障中心资深技术支持工程师,负责公司 SaltStack.StackStorm 等运维平台管理,运维自动化工具开发. 给大家分享的主题是基于 ...

最新文章

  1. TensorFlow中的RNNCell基本单元使用
  2. 无人驾驶推进时间表及五大技术领域关键节点
  3. 传统生成API文档弊端
  4. Vue中computed、methods和watch之间的区别
  5. java辐射汉化_新研究:低强度环境辐射足以导致量子比特退相干
  6. o在linux是什么权限,Linux权限管理基本知识大全
  7. 分布式多副本一致性协议:paxos
  8. JavaScript变量的声明与使用以及命名规范(3)
  9. PHP $_SERVER['PHP_SELF']、$_SERVER['SCRIPT_NAME'] 与 $_SERVER['REQUEST_URI'] 之间的区别
  10. 通过binlog恢复mysql数据库
  11. 82、组合分配式气体灭火系统所需的气体单向阀的数量
  12. Windows查看所有共享
  13. 身份证阅读器二次开发说明
  14. fiddler扩展模拟弱网络环境设置
  15. 解决iPhone连接电脑,照片每次弹出
  16. 飞桨PP-HumanSeg本地实时视频推理代码解读
  17. R中常用统计指标含义
  18. 深入理解Andorid 卷I 第五章
  19. 华为2012实验室无线通信领域的首席专家朱佩英博士
  20. iOS开发中常用到的第三方库

热门文章

  1. 如何给LattePanda重装系统
  2. MES制造执行系统设计与开发
  3. 【转】【重要】推荐系统之数据与特征工程
  4. SPOJ 7258 SUBLEX (SAM)
  5. 不同分辨率图片匹配_杜克大学开源 AI 算法,让马赛克图片秒变高清!
  6. 10月21日绿健简报,星期五,农历九月廿六
  7. 怎么html文件打包,html文件如何打包?html文件打包的方法介绍
  8. 变频器与三相电机的接线图
  9. 深度剖析SSD(你那些似懂非懂的地方)
  10. 前端常用的【文件下载操作2】不获取后端文件流 【纯前端】实现:el-table表格下载为Excel文件【sheetJS XLSX】