/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
package beans.service;
import beans.request.IPPortPair;
import beans.request.ReleasePlan;
import ngse.org.*;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import javax.servlet.ServletOutputStream;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
/**
* Created by Administrator on 2016/2/2.
* 查询某个发布计划的详细信息
*/
public class CarryOutReleasePlan extends JsonRPCHandler {
private String plan_id;
private String flsn;
private String slsn;
private String release_type;
private String release_memo;
public static String showProcessCmds(String flsn, String slsn) {
String ps = "\nsleep 1;echo 'ps|grep srpc...'\n" +
"ps auxw|grep srpc_%s_%s|grep -v grep;echo ''\n" +
"echo 'ps |grep agent...'\n" +
"ps auxw|grep -e monitor_agent -e nlbagent -e flume -e remote_shell_agent |grep -v grep\n";
return String.format(ps, flsn, slsn);
}
//备份起来,用于回滚
private String backupCmdString( boolean isFirstTimeFlag)
{
String s = "";
if (isFirstTimeFlag) {
s = String.format("mkdir -p /msec/backup/\n" +
"if [ -e '/msec/%s/%s' ] ; then\n" +
" cp -R /msec/%s/%s/ /msec/backup/backup_%s\n" +
"fi\n",
flsn, slsn,
flsn, slsn, plan_id);
}
return s;
}
private String geneCmdFileForOnlyConfigRelease(String remoteFileFullName, String remoteFileBaseName, boolean isFirstTimeFlag)
{
String fmt = "rm /msec/%s/%s/etc/config.ini\n"+
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n"+
"cp /tmp/framework/etc/config.ini /msec/%s/%s/etc/\n"+
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop; ./srpc.sh start";
String cmdFileName = ServletConfig.fileServerRootDir+"/tmp/"+ plan_id+".sh";
String content = String.format(fmt,
flsn, slsn, //rm
remoteFileBaseName, //tar xf
plan_id,// rm -rf
flsn, slsn,//cp
flsn, slsn);//restart
content = backupCmdString(isFirstTimeFlag) + content+showProcessCmds(flsn,slsn);
try {
FileOutputStream out = new FileOutputStream(cmdFileName);
out.write(content.getBytes());
out.close();
}
catch ( Exception e)
{
e.printStackTrace();
return "";
}
return cmdFileName;
}
private String geneCmdFileForOnlyLibraryRelease(String remoteFileFullName, String remoteFileBaseName, boolean isFirstTimeFlag)
{
String fmt = "rm -rf /msec/%s/%s/bin/lib\n"+
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n"+
"cp -R /tmp/framework/bin/lib /msec/%s/%s/bin/\n"+
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop;./srpc.sh start";
String cmdFileName = ServletConfig.fileServerRootDir+"/tmp/"+ plan_id+".sh";
String content = String.format(fmt,
flsn, slsn, //rm
remoteFileBaseName, //tar xf
plan_id,// rm -rf
flsn, slsn,//cp
flsn, slsn);//restart
content = backupCmdString(isFirstTimeFlag) + content+showProcessCmds(flsn,slsn);
try {
FileOutputStream out = new FileOutputStream(cmdFileName);
out.write(content.getBytes());
out.close();
}
catch ( Exception e)
{
e.printStackTrace();
return "";
}
return cmdFileName;
}
private String geneCmdFileForOnlySharedobjectRelease(String remoteFileFullName, String remoteFileBaseName, boolean isFirstTimeFlag, String dev_lang)
{
String fmt = "";
//主要差异在第四行:业务插件的名字
if (dev_lang.equals("c++")) {
fmt = "rm /msec/%s/%s/bin/msec.so\n" +
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n" +
"cp /tmp/framework/bin/msec.so /msec/%s/%s/bin\n" +
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop; ./srpc.sh start";
}
else if (dev_lang.equals("java"))
{
fmt = "rm /msec/%s/%s/bin/msec.jar\n" +
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n" +
"cp /tmp/framework/bin/msec.jar /msec/%s/%s/bin\n" +
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop; ./srpc.sh start";
}
else if (dev_lang.equals("php"))
{
fmt = "rm /msec/%s/%s/bin/msec.tgz\n" +
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n" +
"cp /tmp/framework/bin/msec.tgz /msec/%s/%s/bin\n" +
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop; ./srpc.sh start";
}
else if (dev_lang.equals("python"))
{
fmt = "rm /msec/%s/%s/bin/msec_py.tgz\n" +
"cd /tmp; tar zxf %s\n" +
"rm -rf /tmp/framework; mv /tmp/%s /tmp/framework\n" +
"cp /tmp/framework/bin/msec_py.tgz /msec/%s/%s/bin\n" +
"cd /msec/%s/%s/bin;chmod a+x ./*; ./srpc.sh stop; ./srpc.sh start";
}
String cmdFileName = ServletConfig.fileServerRootDir+"/tmp/"+ plan_id+".sh";
String content = String.format(fmt,
flsn, slsn, //rm
remoteFileBaseName, //tar xf
plan_id,// rm -rf
flsn, slsn,//cp
flsn, slsn);//restart
content = backupCmdString(isFirstTimeFlag) + content+showProcessCmds(flsn,slsn);
try {
FileOutputStream out = new FileOutputStream(cmdFileName);
out.write(content.getBytes());
out.close();
}
catch ( Exception e)
{
e.printStackTrace();
return "";
}
return cmdFileName;
}
private String geneCmdFileForCompleteRelease(String remoteFileFullName, String remoteFileBaseName, boolean isFirstTimeFlag)
{
String fmt =
"if [ -e /msec/%s/%s/ ]; then\n" +
"cd /msec/%s/%s/bin/; chmod a+x ./*; ./srpc.sh stop\n"+
"fi\n" +
"mkdir -p /msec/%s/%s\n" +
"rm -rf /msec/%s/%s/*\n"+
"cp %s /msec/%s/%s/\n" +
"cd /msec/%s/%s/ ;tar zxf %s\n" +
"mv /msec/%s/%s/%s/* /msec/%s/%s/\n"+
"cd /msec/%s/%s/bin/; chmod a+x ./*; ./srpc.sh start\n"+
"rm /msec/%s/%s/%s";
String cmdFileName = ServletConfig.fileServerRootDir+"/tmp/"+ plan_id+".sh";
String content = String.format(fmt,
flsn, slsn,//if
flsn, slsn, //stop
flsn, slsn, //mkdir -p
flsn, slsn, // rm -rf
remoteFileFullName, flsn, slsn, //cp
flsn, slsn, remoteFileBaseName, //cd ; tar
flsn, slsn, plan_id, flsn, slsn, //mv
flsn, slsn,//start
flsn, slsn, remoteFileBaseName); //rm
content = backupCmdString(isFirstTimeFlag) + content+showProcessCmds(flsn,slsn);
try {
FileOutputStream out = new FileOutputStream(cmdFileName);
out.write(content.getBytes());
out.close();
}
catch ( Exception e)
{
e.printStackTrace();
return "";
}
return cmdFileName;
}
//safeWrite能够避免因为前端浏览器关闭了连接而导致发布没有执行下去
private void safeWrite(String s, ServletOutputStream out)
{
try
{
out.println(s);
out.flush();
}
catch (Exception e){}
}
private void safeWrite(byte[] b,int offset, int len, ServletOutputStream out)
{
try
{
out.write(b, offset, len);
out.flush();
}
catch (Exception e){}
}
private long getLastCarryoutTime(DBUtil util) throws Exception
{
String sql = "select last_carryout_time from t_release_plan where plan_id=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(plan_id);
Map<String,Object> result = util.findSimpleResult(sql, params);
Object o = result.get("last_carryout_time");
return ((Integer)o).intValue();
}
//检查当前时间距离该计划上次发布的时间 是否 大于 gap秒,避免同时执行。 如果大于就写入当前时间并通过检查
private void checkTime(DBUtil util, long gap, long lastCarryoutTime) throws Exception
{
long cur = new Date().getTime() / 1000;
if (cur < lastCarryoutTime || (cur - lastCarryoutTime ) < gap)
{
Exception e = new Exception("太频密,请稍后执行");
throw e;
}
//更新
String sql = "update t_release_plan set last_carryout_time=? where plan_id=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(cur);
params.add(plan_id);
util.updateByPreparedStatement(sql,params);
}
private void updateReleaseMemo(DBUtil util, IPPortPair ipPortPair) throws Exception
{
String sql = "update t_second_level_service_ipinfo set release_memo=? where ip=? and port=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(release_memo);
params.add(ipPortPair.getIp());
params.add(ipPortPair.getPort());
util.updateByPreparedStatement(sql, params);
}
private void doRelease(String tarFile,
IPPortPair[] ips,
ServletOutputStream out,
boolean isFirstTimeFlag,
String dev_lang,
DBUtil util) throws Exception
{
Logger logger = Logger.getLogger(CarryOutReleasePlan.class);
RemoteShell remoteShell = new RemoteShell();
String remoteFileBaseName = new File(tarFile).getName();
String cmdFile = "";
if (release_type.equals("complete")) {
cmdFile = geneCmdFileForCompleteRelease("/tmp/" + remoteFileBaseName, remoteFileBaseName, isFirstTimeFlag);
}
if (release_type.equals("only_config")) {
cmdFile = geneCmdFileForOnlyConfigRelease("/tmp/" + remoteFileBaseName, remoteFileBaseName, isFirstTimeFlag);
}
if (release_type.equals("only_library")) {
cmdFile = geneCmdFileForOnlyLibraryRelease("/tmp/" + remoteFileBaseName, remoteFileBaseName, isFirstTimeFlag);
}
if (release_type.equals("only_sharedobject")) {
cmdFile = geneCmdFileForOnlySharedobjectRelease("/tmp/" + remoteFileBaseName, remoteFileBaseName, isFirstTimeFlag, dev_lang);
}
logger.info("cmd file:" + cmdFile);
byte[] buf = new byte[10240];
for (int i = 0; i < ips.length; i++) {
String ip = ips[i].getIp();
String result = remoteShell.SendFileToAgent(tarFile,
"/tmp/"+remoteFileBaseName,
ip);
if (result == null || !result.equals("success"))
{
safeWrite(String.format(">>>send file to %s failed:%s", ip, result), out);
continue;
}
out.println(String.format("send file to %s succesfully", ip));
StringBuffer outputFileName = new StringBuffer();
result = remoteShell.SendCmdsToAgentAndRun(cmdFile, ip, outputFileName);
if (result == null || !result.equals("success"))
{
safeWrite(String.format(">>>send cmd file to %s failed:%s", ip, result), out);
continue;
}
safeWrite(String.format("send cmd file to %s succesfully", ip), out);
String localResult = ServletConfig.fileServerRootDir+"/tmp/" + plan_id+".out";
logger.info("run cmd file,get result file:"+localResult);
result = remoteShell.GetFileFromAgent(localResult, outputFileName.toString(), ip);
if (result == null || !result.equals("success"))
{
safeWrite(String.format(">>>get result file from %s failed:%s\n", ip, result), out);
continue;
}
safeWrite(String.format("get result file from %s succesfully\n", ip), out);
FileInputStream in = new FileInputStream(localResult);
while (true)
{
int len = in.read(buf);
if (len < 0)
{
break;
}
safeWrite(buf, 0, len, out);
}
in.close();
safeWrite("--------------------------", out);
//更新该IP的版本信息
updateReleaseMemo(util, ips[i]);
}
out.println("done!");
}
private void updatePlanStatus(DBUtil util, String status) throws Exception
{
String sql = "update t_release_plan set status=? where plan_id=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(status);
params.add(plan_id);
util.updateByPreparedStatement(sql, params);
}
String getDevLang(DBUtil util, String flsn, String slsn) throws Exception
{
util.getConnection();
String sql = "select dev_lang from t_second_level_service where first_level_service_name=? and second_level_service_name=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(flsn);
params.add(slsn);
Map<String, Object> map = util.findSimpleResult(sql, params);
return (String) map.get("dev_lang");
}
public JsonRPCResponseBase exec(ReleasePlan request)
{
Logger logger = Logger.getLogger(CarryOutReleasePlan.class);
JsonRPCResponseBase resp = new JsonRPCResponseBase();
plan_id = request.getPlan_id();
flsn = request.getFirst_level_service_name();
slsn = request.getSecond_level_service_name();
logger.info( String.format("carry out plan begin\n [%s.%s][%s]\n", flsn, slsn, plan_id));
if (flsn == null || flsn.length() < 1 ||
slsn == null || slsn.length() < 1||
plan_id == null || plan_id.length() < 1)
{
resp.setStatus(100);
resp.setMessage("service name/plan id invalid!");
return resp;
}
String result = checkIdentity();
if (!result.equals("success"))
{
resp.setStatus(99);
resp.setMessage(result);
return resp;
}
DBUtil util = new DBUtil();
if (util.getConnection() == null)
{
resp.setStatus(100);
resp.setMessage("db connect failed!");
return resp;
}
try {
String sql = "select dest_ip_list, memo,release_type from t_release_plan where plan_id=?";
ArrayList<Object> params = new ArrayList<Object>();
params.add(request.getPlan_id());
Map<String, Object> res = util.findSimpleResult(sql,params);
if (res.get("dest_ip_list") == null )
{
resp.setStatus(100);
resp.setMessage("query dest ip list failed.");
return resp;
}
String dest_ip_list = (String)(res.get("dest_ip_list"));
release_memo = (String)(res.get("memo"));
release_type = (String)(res.get("release_type"));
release_memo = plan_id.substring(4, 12) + release_memo;
ObjectMapper objectMapper = new ObjectMapper();
IPPortPair[] ips = objectMapper.readValue(dest_ip_list, IPPortPair[].class);
logger.info("destination IP number;"+ips.length);
long gap = ips.length * 60; //每一个目标ip执行耗时估计30s,
long lastCarryoutTime = getLastCarryoutTime(util);
checkTime(util,gap, lastCarryoutTime);
logger.info("check last carry out time OK");
//对每个IP下发安装包
String tarFile = PackReleaseFile.getPackedFile(request.getPlan_id());
logger.info("release package path:" + tarFile);
getHttpResponse().setContentType("text/html");
getHttpResponse().setCharacterEncoding("UTF-8");
ServletOutputStream out = getHttpResponse().getOutputStream();
safeWrite("<html>", out);
safeWrite("<head>", out);
safeWrite("<title>release result</title>", out);
safeWrite("</head>", out);
safeWrite("<body>", out);
safeWrite("<pre>", out);//这个标签用于原样输出
updatePlanStatus(util, "carrying out");
String dev_lang = getDevLang(util, flsn,slsn);
doRelease(tarFile, ips, out, lastCarryoutTime == 0, dev_lang, util);
safeWrite("</pre>", out);
safeWrite("</body>", out);
safeWrite("</html>", out);
//update plan status
updatePlanStatus(util, "carry out successfully");
try {out.close();}catch (Exception e){}
return null;
}
catch (Exception e)
{
resp.setStatus(100);
resp.setMessage(e.getMessage());
e.printStackTrace();
try {
updatePlanStatus(util, "failed to carry out");
}
catch (Exception e1){}
return resp;
}
finally {
util.releaseConn();
}
}
}