您好,登錄后才能下訂單哦!
1、需求
之前一直是手動的巡檢,然后貼圖,最近服務器數量大增,有點忙不過來了。因為一直用的java,對shell腳本不是特別了解,所以這次用java寫了個小項目,實現對多服務器,多任務的巡檢,巡檢結果有故障的會通過郵件通知。
2、功能和效果
巡檢的項目主要是服務,硬盤,內存等,命令可配置,巡檢結果以日期和服務器為基準輸出文件,錯誤信息通過郵件通知管理運維人員。
3、代碼
action:
package com.save.action; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; import com.save.pojo.Cmd; import com.save.until.MailUtil; import com.save.until.PropertiesUtil; import com.save.until.SSHCommUtil; import com.save.until.WriteUntil; /** * 巡檢任務 * @author zhangzhuo * */ public class InspAction { final static Logger logger = LoggerFactory.getLogger(InspAction.class); /* public static void main(String[] args) { InspAction n = new InspAction(); try { n.execute(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); logger.error("dd"); } }*/ /** * 執行巡檢任務 * @param args */ public void execute() throws Exception{ List<Cmd> list = this.handlerData(); Set<String> mail = new HashSet<String>(); for (Cmd cmd : list) { String ip = cmd.getIp(); int port = 22; String localIp = null; int localPort = 0; int timeOut = 6000; String userName = cmd.getUsername(); String password = cmd.getPassword(); String server = cmd.getServer(); String[] cmds = cmd.getCmds(); String[] result = null; logger.info(ip+"執行巡檢任務開始"); try { result = SSHCommUtil.execShellCmdBySSH(ip, port, localIp, localPort, timeOut, userName, password, cmds); } catch (Exception e) { e.printStackTrace(); logger.error(ip+"巡檢,服務器連接不上"); mail.add(ip+" "+"巡檢,服務器連接不上"); } Date date = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); String dateString = formatter.format(date); //1、服務存活驗證 2、硬盤占用驗證 3、巡檢結果寫入文件 if (result != null) { for (String string : result) { if (string.contains("ps -ef|grep java")||string.contains("ps -ef|grep mongo")||string.contains("ps -ef|grep redis")) { if (!string.contains(server)) { mail.add(ip+" "+server+"服務不存在"); } } if (string.contains("df -h")) { String patt = "^[5]\\d{1}\\%|[5-9]\\d{1}\\%|\\d{3,}\\%$"; String group = null; Pattern p = Pattern.compile(patt); Matcher m = p.matcher(string); while (m.find()) { group = m.group(); } if (!StringUtils.isBlank(group)) { mail.add(ip+" "+"硬盤占用超出預警線"); } } WriteUntil.createFile("E:\\save", dateString, "\\"+ip+".txt", string); } logger.info(ip+"巡檢結束"); } } //發送故障郵件通知 if (!mail.isEmpty()||mail.size()!=0) { MailUtil.getInstance().sendMail(mail); } } /** * 數據處理 * @return */ private List<Cmd> handlerData(){ logger.info("開始加載需要巡檢的服務器數據"); Cmd cmd = null; List<Cmd> list = new ArrayList<Cmd>(); Map map = PropertiesUtil.getInstance().getAllProperty(); Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); cmd =new Cmd(); cmd.setIp(entry.getKey()); Cmd cmd2 = JSON.parseObject(entry.getValue(), Cmd.class); String[] cmds = cmd2.getShell().split(","); cmd.setCmds(cmds); cmd.setServer(cmd2.getServer()); cmd.setUsername(cmd2.getUsername()); cmd.setPassword(cmd2.getPassword()); list.add(cmd); } logger.info("數據加載完畢"); return list; } }
pojo:
package com.save.pojo; public class Cmd { private String ip; private String username; private String password; private String shell; private String[] cmds; private String server; public String getServer() { return server; } public void setServer(String server) { this.server = server; } public String getShell() { return shell; } public void setShell(String shell) { this.shell = shell; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String[] getCmds() { return cmds; } public void setCmds(String[] cmds) { this.cmds = cmds; } }
工具類:
package com.save.until; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.jcraft.jsch.SocketFactory; /** * SSH創建與服務器連接工具類 * @author 張卓 * 2017-4-21 */ public class JSCHUtil { final static Logger logger = LoggerFactory.getLogger(JSCHUtil.class); private static JSch jsch = new JSch(); /** * 創建Session,并打開Session連接 * */ public static Session createSession(String dstIp, int dstPort, final String localIp, final int localPort, String userName, String password, final int timeOut) throws JSchException { //jsch.setKnownHosts("/home/foo/.ssh/known_hosts"); logger.info("開始連接:"+dstIp); // 建立一個SSH連接 Session session = jsch.getSession(userName, dstIp, dstPort); session.setPassword(password); Properties sshConfig = new Properties(); sshConfig.put("StrictHostKeyChecking", "no");//跳過主機檢查 session.setConfig(sshConfig); // 此socket工廠用于創建目標主機的socket, // 并創建我們使用的這個socket字節流 session.setSocketFactory(new SocketFactory() { public OutputStream getOutputStream(Socket socket) throws IOException { return socket.getOutputStream(); } public InputStream getInputStream(Socket socket) throws IOException { return socket.getInputStream(); } public Socket createSocket(String host, int port) throws IOException, UnknownHostException { Socket socket = new Socket(); if (localIp != null) { socket.bind(new InetSocketAddress(InetAddress .getByName(localIp), localPort)); } socket.connect( new InetSocketAddress(InetAddress.getByName(host), port), timeOut); return socket; } }); session.connect(timeOut); return session; } }
package com.save.until; import java.util.Properties; import java.util.Set; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.mail.util.MailSSLSocketFactory; /** * 郵件發送 * @author zhangzhuo * */ public class MailUtil { final static Logger logger = LoggerFactory.getLogger(MailUtil.class); private static MailUtil instance = new MailUtil(); private MailUtil (){} public static MailUtil getInstance() { return instance; } public void sendMail(Set<String> mail) { String from = "XXX@qq.com";// 發件人電子郵箱 String host = "smtp.qq.com"; // 指定發送郵件的主機smtp.qq.com(QQ)|smtp.163.com(網易) Properties properties =new Properties(); properties.setProperty("mail.smtp.host", host);// 設置郵件服務器 properties.setProperty("mail.smtp.auth", "true");// 打開認證 try { //QQ郵箱需要下面這段代碼,163郵箱不需要 MailSSLSocketFactory sf = new MailSSLSocketFactory(); sf.setTrustAllHosts(true); properties.put("mail.smtp.ssl.enable", "true"); properties.put("mail.smtp.ssl.socketFactory", sf); // 1.獲取默認session對象 Session session = Session.getDefaultInstance(properties, new Authenticator() { public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("XXX@qq.com", "XXX"); // 發件人郵箱賬號、授權碼 } }); // 2.創建郵件對象 Message message = new MimeMessage(session); message.setFrom(new InternetAddress(from)); message.addRecipient(Message.RecipientType.TO, new InternetAddress("XXX@qq.com")); message.setSubject("巡檢故障通知"); StringBuffer sb = new StringBuffer(); for (String string : mail) { sb.append("<div>"+string+"</div><br/><hr/>"); } String content = sb.toString(); message.setContent(content, "text/html;charset=UTF-8"); Transport.send(message); logger.info("故障郵件發送成功"); } catch (Exception e) { e.printStackTrace(); } } }
package com.save.until; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URI; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * 讀取文件工具類 * @author zhangzhuo * */ public class PropertiesUtil { private Properties props; private URI uri; private static PropertiesUtil ourInstance = new PropertiesUtil("/config.properties"); public static PropertiesUtil getInstance() { return ourInstance; } public PropertiesUtil(String fileName){ readProperties(fileName); } private void readProperties(String fileName) { try { props = new Properties(); InputStream fis =getClass().getResourceAsStream(fileName); InputStreamReader re=new InputStreamReader(fis,"utf-8"); props.load(re); } catch (Exception e) { e.printStackTrace(); } } /** * 獲取某個屬性 */ public String getProperty(String key){ return props.getProperty(key); } /** * 獲取所有屬性,返回一個map,不常用 * 可以試試props.putAll(t) */ public Map getAllProperty(){ Map map=new HashMap(); Enumeration enu = props.propertyNames(); while (enu.hasMoreElements()) { String key = (String) enu.nextElement(); String value = props.getProperty(key); map.put(key, value); } return map; } /** * 在控制臺上打印出所有屬性,調試時用。 */ public void printProperties(){ props.list(System.out); } /** * 寫入properties信息 */ public void writeProperties(String key, String value) { try { OutputStream fos = new FileOutputStream(new File(uri)); props.setProperty(key, value); // 將此 Properties 表中的屬性列表(鍵和元素對)寫入輸出流 props.store(fos, "『comments』Update key:" + key); } catch (Exception e) { e.printStackTrace(); } } }
package com.save.until; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jcraft.jsch.Channel; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; /** * 執行Shell工具類 * @author zhangzhuo * */ public class SSHCommUtil { final static Logger logger = LoggerFactory.getLogger(SSHCommUtil.class); /** * SHH連接Linux Shell,返回結果 */ public static String[] execShellCmdBySSH(String dstIp, int dstport, String localIp, int localPort, int timeOut, String userName, String password, String... cmds) throws Exception { Session session = null; Channel channel = null; InputStream is = null; OutputStream os = null; try { session = JSCHUtil.createSession(dstIp, dstport, localIp, localPort, userName, password, timeOut); logger.info("開始創建channel通道!"); //創建一個channel類型的通道 channel = session.openChannel("shell"); // Enable agent-forwarding. // ((ChannelShell)channel).setAgentForwarding(true); // Choose the pty-type "vt102". // ((ChannelShell)channel).setPtyType("vt102"); // Set environment variable "LANG" as "ja_JP.eucJP". // ((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP"); channel.connect(); is = channel.getInputStream(); os = channel.getOutputStream(); String[] result = new String[cmds.length]; for (int i = 0; i < cmds.length; i++) { result[i] = sendCommand(is, os, cmds[i]); } return result; } catch (JSchException e) { if (e.getMessage().contains("Auth fail")) { logger.error(dstIp+"服務器驗證失敗"); throw new Exception("Auth error"); } else { logger.error(dstIp+"服務器連接失敗"); throw new Exception("Connect error"); } } catch (Exception e) { throw e; } finally { try { is.close(); } catch (IOException e) { } try { os.close(); } catch (IOException e) { } channel.disconnect(); session.disconnect(); } } /** *執行Shell腳本并返回結果 * */ private static String sendCommand(InputStream is, OutputStream os, String cmd) throws IOException { logger.info("開始執行腳本!"); os.write(cmd.getBytes()); os.flush(); StringBuffer sb = new StringBuffer(); int beat = 0; while (true) { if (beat > 3) { break; } if (is.available() > 0) { byte[] b = new byte[is.available()]; is.read(b); sb.append(new String(b)); beat = 0; } else { if (sb.length() > 0) { beat++; } try { Thread.sleep(sb.toString().trim().length() == 0 ? 1000 : 300); } catch (InterruptedException e) { } } } return sb.toString(); } }
package com.save.until; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; /** * SSH工具類 * */ public class SSHExcuteCommandHelper { Session session = null; ChannelExec openChannel = null; /** * @param host 主機ip * @param name 用戶名 * @param pwd 密碼 * @param port ssh端口 */ public SSHExcuteCommandHelper(String host, String user, String pwd, int port) { JSch jsch = new JSch(); try { session = jsch.getSession(user, host, port); java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setTimeout(1000); session.setConfig(config); session.setPassword(pwd); } catch (JSchException e) { e.printStackTrace(); } } /** * 是否連接成功,調用如果不需要調用execCommand方法那么必須調用 disconnect方法關閉session * @return */ public boolean canConnection(){ try { session.connect(); return true; } catch (JSchException e) { e.printStackTrace(); return false; } } /** * 關閉連接 */ public void disconnect(){ if (openChannel != null && !openChannel.isClosed()) { openChannel.disconnect(); } if (session != null && session.isConnected()) { session.disconnect(); } } /** * 執行命令 * @param command * @return */ public String execCommand(String command) { StringBuffer result = new StringBuffer(); try { if(!session.isConnected()){ session.connect(); } openChannel = (ChannelExec) session.openChannel("exec"); openChannel.setCommand(command); //int exitStatus = openChannel.getExitStatus(); openChannel.connect(); InputStream in = openChannel.getInputStream(); BufferedReader reader = new BufferedReader( new InputStreamReader(in)); String tmpStr = ""; while ((tmpStr = reader.readLine()) != null) { result.append(new String(tmpStr.getBytes("gbk"), "UTF-8")).append("\n"); } } catch (Exception e) { e.printStackTrace(); result.append(e.getMessage()); } finally { disconnect(); } return result.toString(); } /** * 解析 * @param result * @return */ public List<List<String>> parseResult(String result){ List<List<String>> parseResult = new ArrayList<List<String>>(); List<String> list = null; // for (String line : result.split("\n")) { list = new ArrayList<String>(); String[] columns = {}; //這個是針對df命令的 [Mounted on] 其實就一個,如果用空格就會分割出兩個 if(line.contains("Mounted ")){ columns = line.replace("Mounted ", "Mounted-").split(" "); }else{ columns = line.split(" "); } for (String column : columns) { if (!" ".equals(column) && !"".equals(column)) { list.add(column); } } parseResult.add(list); } return parseResult; } //測試 /* public static void main(String args[]) { SSHExcuteCommandHelper execute = new SSHExcuteCommandHelper("192.168.175.128", "root", "123456", 22); System.out.println("是否連接成功"+execute.canConnection()); String s = execute.execCommand("free -m"); System.out.println("解析前"); System.out.println(s); System.out.println("解析后"); List<List<String>> parseResult = execute.parseResult(s); for (List<String> l : parseResult) { System.out.println(l); } }*/ }
package com.save.until; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.save.action.InspAction; /** * * @author zhangzhuo * */ public class WriteUntil { final static Logger logger = LoggerFactory.getLogger(WriteUntil.class); /** * 新建文件夾,并創建文件寫入數據 */ public static void createFile(String basePath,String filePath, String filename, String input) { String[] dirs = filePath.split("/"); String tempPath = basePath; for (String dir : dirs) { if (null == dir || "".equals(dir)) continue; tempPath += "\\" + dir; } //文件夾判斷 File dir = new File(tempPath);//"d:\\test_dir" if (dir.exists()) { if (dir.isDirectory()) { logger.info("文件夾存在"); } else { logger.info("同名文件存在,無法創建目錄"); } } else { logger.info("文件夾不存在,開始創建"); dir.mkdirs(); } //文件判斷 File file = new File(tempPath+filename);//"d:\\test_file.txt" if (file.exists()) { logger.info(filename+"已存在"); } else { logger.info(filename+"文件不存在,開始創建"); try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } //寫入數據 //方法一、每次寫入覆蓋之前的 /* try { FileOutputStream fos = new FileOutputStream(tempPath+filename); fos.write(input.getBytes()); fos.close(); } catch (Exception e) { e.printStackTrace(); }*/ try { FileOutputStream fos = new FileOutputStream(tempPath+filename, true); fos.write(input.getBytes()); fos.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //測試 /* public static void main(String[] args) { //createFile("E:\\log", "2014/16/2/", "\\2020.txt", "hahha"); Date date = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); String dateString = formatter.format(date); System.out.println(dateString); }*/ }
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 配置作業類 --> <bean id="InspAction" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <bean class="com.save.action.InspAction" /> </property> <property name="targetMethod" value="execute" /> <property name="concurrent" value="false" /><!-- 作業不并發調度 --> </bean> <!-- 配置觸發器 --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="InspAction" /> <!-- 每天7:00運行一次 --> <property name="cronExpression" value="0 0 07 * * ?" /> </bean> <!-- 配置調度工廠 --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean> </beans>
config.properties
#測試用服務器 192.168.175.128={"username":"root","password":"123456","shell":"ps -ef|grep mongo\n,df -h\n, free -m\n, top\n","server":"mongod"} 192.168.175.129={"username":"root","password":"123456","shell":"ps -ef|grep redis\n,df -h\n, free -m\n, top\n","server":"mongod"} log4j.properties
#指定根Logger,及日志輸出級別 #大于等于該級別的日志將被輸出( DEBUG < INFO < WARN < ERROR < FATAL ),設為OFF可以關閉日志 log4j.rootLogger=INFO, A1,A2 #指定log輸出目的,這里設為輸出日志到指定目錄的文件my.log中 log4j.appender.A1=org.apache.log4j.FileAppender log4j.appender.A1.File=E:\\save\\log\\xj.log #指定日志信息的格式 log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n #把A2輸出到控制臺 log4j.appender.A2=org.apache.log4j.ConsoleAppender log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n
pom.xml:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.save</groupId> <artifactId>save-xj</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>save-xj Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- SSH連接 --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.53</version> </dependency> <!-- json轉換 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.31</version> </dependency> <!-- Spring的包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.0.5.RELEASE</version> </dependency> <!-- 定時任務 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>1.8.5</version> </dependency> <!-- 日志的包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> <!-- 郵件 --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.4.4</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。