package com.suteam.zsyun.job;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.log4j.Logger;
import com.alibaba.fastjson.JSON;
import com.suteam.zsyun.application.model.ApplicationFilePack;
import com.suteam.zsyun.commonUtil.FileUtil;
import com.suteam.zsyun.commonUtil.HttpAuthUtil;
import com.suteam.zsyun.commonUtil.ModifyConfig;
import com.suteam.zsyun.config.Config;
public class BasicJobUtil {
public static Logger log = Logger.getLogger(BasicJobUtil.class);
public static void executeTask() {
log.info(" *****agent守護程序定時任務開始***** ");
try {
// 擷取jar檔案目前路徑
String path = System.getProperty("user.dir");
log.info("jar檔案目前路徑:"+path);
// 擷取配置檔案路徑
String configPath = FileUtil.getConfigPath();
// 讀取配置檔案config.ini,擷取版本号version_Number與目前jar檔案名稱
Properties configProperty = FileUtil.getConfig(configPath + Config.configName);
String versionNumber = configProperty.getProperty("version_Number");
String agentName = configProperty.getProperty("agent_Name");
// 讀取配置檔案es.ini,擷取code
Properties esProperty = FileUtil.getConfig(configPath + Config.esName);
String code = esProperty.getProperty("code");
// 讀取配置檔案watch.ini,擷取app項目伺服器位址
Properties watchProperty = FileUtil.getConfig(configPath + Config.watchName);
String appServer = watchProperty.getProperty("appServer");
// 聲明一個存放請求參數的map
Map<String, String> parameterMap = new HashMap<String, String>();
// 拼接調用app項目中的版本查詢接口的url和參數
String url = appServer + "/v1/port/appService/query/queryPatch.do";
parameterMap.put("code", code);
parameterMap.put("versionNumber", versionNumber);
// 調用APP項目中版本查詢接口
log.info("調用APP項目中版本查詢接口:");
String result = HttpAuthUtil.doAuthPost(url, parameterMap);
Map<String, Object> mapResult = (Map<String, Object>) JSON.parse(result);
if (null != mapResult && "ok".equals(mapResult.get("result"))) {
log.info("調用APP項目中版本查詢接口,ok:");
// 解析擷取應用檔案包對象
ApplicationFilePack applicationFilePack = JSON.parseObject(String.valueOf(mapResult.get("values")),
ApplicationFilePack.class);
// 判斷應用檔案包對象是否為空。不為空說明有要更新的agent。
if (null != applicationFilePack) {
log.info("檔案包對象不為空,說明有要更新的agent。");
// 擷取版本
String version = applicationFilePack.getVersion();
log.info("擷取新版本version:" + version);
if (!version.equals(versionNumber)) {
log.info("新舊版本不同。");
// 擷取應用檔案路徑
String filePath = applicationFilePack.getFilePath();
log.info("新檔案路徑:"+filePath);
// 擷取檔案hash
String hash = applicationFilePack.getHash();
log.info("新檔案hash:"+hash);
// 擷取名稱,如agent_1.2.jar
String name = applicationFilePack.getName();
log.info("新檔案名稱:" + name);
// 調用下載下傳更新檔方法
String getHash = downLoadFromUrl(filePath, name, path);
if (!getHash.equals(hash)) {
// 将下載下傳失敗的檔案删除
if (path.contains("/")) {
path += "/";
}
if (path.contains("\\")) {
path += "\\";
}
log.info("将下載下傳失敗的檔案删除,要删除的檔案為:"+path + name);
deleteFile(path + name);
// hash不同,下次定時任務重新下載下傳
log.info("hash不同,下次定時任務重新下載下傳");
} else {
log.info("新下載下傳的jar檔案與原檔案hash相同。");
// 修改配置檔案,将檔案版本更新成新版本
log.info("修改配置檔案更新版本資訊:");
String[] keyArray = new String[2];
keyArray[0] = "version_Number";
keyArray[1] = "agent_Name";
String[] valueArray = new String[2];
valueArray[0] = version;
valueArray[1] = name;
log.info("新的版本為:" + version);
String fileName = "config.ini";
ModifyConfig.modifyConfig(keyArray, valueArray, fileName);
log.info("修改配置檔案更新版本資訊,完成。");
log.info("将原agent停止:");
if (path.contains("/")) {
path += "/";
log.info("Linux将原agent停止:");
String psCommander = "ps -ef|grep "+agentName;
log.info("檢視程序指令:" + psCommander);
Process ps = Runtime.getRuntime().exec(new String[] { "sh", "-c", psCommander });
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
String ret = sb.toString();
// 将擷取結果去除回車拆分
String[] resultStr = ret.split("\n");
for (int j = 0; j < resultStr.length; j++) {
String s = resultStr[j];
// 去除tab鍵
s = s.replace(" ", " ");
log.info("去除tab鍵:" + s);
// 将所有的多空格轉成單空格
s = s.replaceAll(" +", " ");
log.info("将所有的多空格轉成單空格:" + s);
if (s.startsWith(" ")) {
// 将第一個空格截取去除
s = s.substring(1, s.length());
log.info("将第一個空格截取去除:" + s);
}
// 将資料以空格拆分:root 16608 4888 0 15:08 pts/1
// 00:00:47 java -jar agent.jar
String[] retStr = s.split(" ");
log.info("将資料以空格拆分:" + s);
// 擷取程序結果的最後一個資料(所下達的指令為何)
String cmdCommander = "";
for (int i = 7; i < retStr.length; i++) {
cmdCommander = cmdCommander + retStr[i];
}
log.info("logCode程序結果的最後一個資料:" + cmdCommander);
log.info("pid為:" + retStr[1]);
if (cmdCommander.contains("java-jar")) {
// 包含檔案名,說明這個程序為要殺死的agent程序。擷取程序的pid(第二個資料)。
String pid = retStr[1];
log.info("pid為:" + retStr[1]);
// 擷取cp程序的辨別号,拼接殺程序指令kill -9 程序辨別号
String killCommander = "kill -9 " + pid;
// 執行殺程序指令
log.info("---開始執行kill指令:" + killCommander);
Runtime.getRuntime().exec(killCommander);
log.info("---執行kill指令完畢。");
}
}
// 檔案路徑
String shfileName = path+"/restarJar.sh";
log.info("擷取sh檔案路徑如下 :"+shfileName);
// 1.删除檔案
deleteFile(shfileName);
log.info("删除檔案完成。");
// 2.建立檔案
createNewFile(shfileName);
log.info("建立檔案完成。");
//changeParam為要追加到.sh檔案的資訊
String changeParam = "nohup java -jar /usr/agenthost/" + name +" > /usr/agenthost/logs/myout.file 2>&1 &";
log.info("追加到.sh檔案的資訊:"+ changeParam);
// 3.追加内容 \n代表回車換行
StringBuffer strBuffer = new StringBuffer();
strBuffer.append("#!/bin/sh\n");
strBuffer.append(changeParam);
appendMethod(shfileName, strBuffer.toString());
log.info("追加完成");
log.info("執行sh檔案:bash "+path+"/restarJar.sh");
Runtime.getRuntime().exec("bash "+path+"/restarJar.sh");
log.info("執行sh檔案完成");
}
if (path.contains("\\")) {
path += "\\";
log.info("Windows将原agent停止:");
// 檢視Windows系統所有正在運作的java程式
String psCommander = "jps -l";
log.info("檢視程序指令:" + psCommander);
Process ps = Runtime.getRuntime().exec(psCommander);
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
String ret = sb.toString();
// 将擷取結果去除回車拆分
String[] resultStr = ret.split("\n");
for (int j = 0; j < resultStr.length; j++) {
String s = resultStr[j];
// 去除tab鍵
s = s.replace(" ", " ");
log.info("去除tab鍵:" + s);
// 将所有的多空格轉成單空格
s = s.replaceAll(" +", " ");
log.info("将所有的多空格轉成單空格:" + s);
if (s.startsWith(" ")) {
// 将第一個空格截取去除
s = s.substring(1, s.length());
log.info("将第一個空格截取去除:" + s);
}
// 将資料以空格拆分:root 16608 4888 0 15:08 pts/1
// 00:00:47 java -jar agent.jar
String[] retStr = s.split(" ");
log.info("将資料以空格拆分:" + s);
// 擷取程序結果的最後一個資料(所下達的指令為何)
if(retStr.length>1){
String cmdCommander = retStr[1];
log.info("logCode程序結果的最後一個資料:" + cmdCommander);
if (cmdCommander.contains(agentName)) {
// 包含檔案名,說明這個程序為要殺死的agent程序。擷取程序的pid(第二個資料)。
String pid = retStr[0];
log.info("pid為:" + retStr[0]);
// 擷取cp程序的辨別号,拼接殺程序指令kill -9 程序辨別号
String killCommander = "TASKKILL /F /PID " + pid;
// 執行殺程序指令
log.info("---開始執行kill指令:" + killCommander);
Runtime.getRuntime().exec(killCommander);
log.info("---執行kill指令完畢。");
}
}
}
// 重新開機jar檔案路徑
String shfileName = path+"\\restarJar.bat";
log.info("擷取重新開機jar檔案路徑如下 :"+shfileName);
// 删除原檔案
deleteFile(shfileName);
log.info("删除原檔案完成。");
// 重新建立檔案
createNewFile(shfileName);
log.info("重新建立檔案完成。");
//changeParam為要追加到.sh檔案的資訊
String changeParam = "start javaw -jar " + name;
log.info("追加到.bat檔案的資訊:"+ changeParam);
// 将内容追加到重新開機bat檔案中 \n代表回車換行
StringBuffer strBuffer = new StringBuffer();
strBuffer.append("@echo off\n");
strBuffer.append(changeParam+"\n");
strBuffer.append("success& exit\n");
appendMethod(shfileName, strBuffer.toString());
log.info("追加完成");
log.info("執行重新開機jarbat檔案");
String cmd = "cmd.exe /c start " + shfileName;
Runtime.getRuntime().exec(cmd);
log.info("執行重新開機jarbat檔案完成");
}
}
}
}
} else {
log.info("擷取對象為空,沒有要更新的!");
}
} catch (Exception e) {
log.info("agent守護程序抛出異常。");
}
log.info(" *****agent守護程序定時任務結束*****");
}
public static String getMD5Checksum(String filename) throws Exception {
log.info("進入擷取hash方法:");
byte[] b = createChecksum(filename);
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);// 加0x100是因為有的b[i]的十六進制隻有1位
}
return result;
}
public static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);// 20px;">将流類型字元串轉換為String類型字元串</span>
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5"); // 如果想使用SHA-1或SHA-256,則傳入SHA-1,SHA-256
int numRead;
do {
numRead = fis.read(buffer); // 從檔案讀到buffer,最多裝滿buffer
if (numRead > 0) {
complete.update(buffer, 0, numRead); // 用讀到的位元組進行MD5的計算,第二個參數是偏移量
}
} while (numRead != -1);
fis.close();
return complete.digest();
}
public static void deleteFile(String fileName) {
File file = new File(fileName);
// 如果是檔案,非目錄
if (file.isFile()) {
file.delete();
} else {
return;
}
}
public static void createNewFile(String fileName) {
File file = new File(fileName);
// 如果檔案不存在,建立一個檔案
if (file.isFile() && !file.exists()) {
try {
// 建立檔案
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void appendMethod(String fileName, String content) {
try {
// 打開一個寫檔案器,構造函數中的第二個參數true表示以追加形式寫檔案
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileName, true), "GBK");
osw.write(content);
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String downLoadFromUrl(String urlStr, String fileName, String savePath) throws IOException {
String retHash = "";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 設定逾時間為3秒
conn.setConnectTimeout(3 * 1000);
// 防止屏蔽程式抓取而傳回403錯誤
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 得到輸入流
InputStream inputStream = conn.getInputStream();
// 擷取自己數組
byte[] getData = readInputStream(inputStream);
// 檔案儲存位置
File saveDir = new File(savePath);
if (!saveDir.exists()) {
saveDir.mkdir();
}
File file = new File(saveDir + File.separator + fileName);
FileOutputStream fos = new FileOutputStream(file);
fos.write(getData);
if (fos != null) {
fos.close();
}
if (inputStream != null) {
inputStream.close();
}
log.info("info:" + url + " download success");
// 下載下傳完畢,對更新檔(或agent)進行hash處理
try {
if (savePath.contains("/")) {
savePath += "/";
}
if (savePath.contains("\\")) {
savePath += "\\";
}
log.info("hash路徑:" + savePath + fileName);
retHash = getMD5Checksum(savePath + fileName);
} catch (Exception e) {
e.printStackTrace();
}
log.info("擷取的檔案hash:" + retHash);
return retHash;
}
public static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
public static void main(String[] args) {
try {
String hash = getMD5Checksum("H:\\agent_v1.2.jar");
System.out.println(hash);
} catch (Exception e) {
e.printStackTrace();
}
}
}
轉載于:https://my.oschina.net/u/3037187/blog/874759