You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

755 lines
22 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Security.Cryptography;
using Sog;
using Sog.IO;
using Google.Protobuf.WellKnownTypes;
using Google.Protobuf;
using System.Linq;
using Enum = Google.Protobuf.WellKnownTypes.Enum;
namespace SMAgent
{
public class SMAgentCommand : Singleton<SMAgentCommand>
{
// 显示的内存单位
private readonly int MEM_UNIT = 1024 * 1024;
private Queue<SMAgentDoCommandReq> m_cmdQueue = new Queue<SMAgentDoCommandReq>();
private SMAgentDoCommandReq m_nowCmd = null;
private long m_nowCmdStartTimeSecond = 0;//超时用
private SMAgentDoCommandRes m_nowCmdRes = null; //回应
private bool m_nowCmdDoFinish = false;
private Thread m_workThread;
private object m_locker = new object();
private bool m_bRunning = true;
private void CheckStart()
{
if (m_workThread == null)
{
m_workThread = new Thread(WorkThreadFun);
m_workThread.Start();
}
}
public void Stop()
{
m_bRunning = false;
}
private void WorkThreadFun()
{
while(m_bRunning)
{
try
{
bool needDoCmd = false;
lock (m_locker)
{
if (m_nowCmd != null && m_nowCmdDoFinish == false)
{
needDoCmd = true;
}
}
if(needDoCmd)
{
var res = DoCommand(m_nowCmd);
lock (m_locker)
{
m_nowCmdRes = res;
m_nowCmdDoFinish = true;
}
}
Thread.Sleep(10);
}
catch(Exception ex)
{
TraceLog.Exception(ex);
}
}
}
public void Update(long tMs)
{
lock (m_locker)
{
//取出新的请求,工作线程会处理这个cmd
if (m_nowCmd == null && m_nowCmdDoFinish == false && m_cmdQueue.Count > 0)
{
m_nowCmdStartTimeSecond = SMAgentUtils.GetTimeSecond();
m_nowCmdRes = null;
m_nowCmdDoFinish = false;
m_nowCmd = m_cmdQueue.Dequeue();
}
//有正在执行的命令
//这个说明这个命令执行完成了,工作线程完成了这个任务,那么主线程回应消息
if (m_nowCmd != null && m_nowCmdDoFinish)
{
if (m_nowCmdRes != null)
{
SMAgentNet.Instance.SendMsgToCenter(m_nowCmdRes, SMMsgID.AgentDoCommandRes);
}
m_nowCmdDoFinish = false;
m_nowCmdStartTimeSecond = 0;
m_nowCmdRes = null;
//这个m_nowCmd赋值放在最后,工作线程以这个m_nowCmd是否为空来判断是否有任务处理
m_nowCmd = null;
}
}
}
public void OnCommand(SMAgentDoCommandReq req)
{
m_cmdQueue.Enqueue(req);
//开启工作线程
CheckStart();
}
private SMAgentDoCommandRes DoCommand(SMAgentDoCommandReq req)
{
switch (req.Command)
{
case "start":
return DoStartCommand(req);
case "stop":
return DoStopCommand(req);
case "hotfix":
return DoHotfixCommand(req);
case "reloadconfig":
return DoReloadConfigCommand(req);
case "reloadcluster":
return DoReloadClusterCommand(req);
case "check":
case "list":
return DoCheckCommand(req);
case "kill":
return DoKillCommand(req);
case "gmcmd":
return DoGmCmdCommand(req);
case "updateagent":
return DoUpdateAgentCommand(req);
case "checkagent":
case "checkpushfile":
return DoCheckAgentCommand(req);
case "shell":
return DoShellCommand(req);
case "cancelshell":
return DoCancelShellCommand(req);
case "pull":
case "pullagentlog":
return DoPullFileCmd(req);
case "checkagentmem":
return DoCheckAgentMemCmd(req);
default:
TraceLog.Error("SMAgentCommand.DoCommand invalid cmd {0}", req.Command);
return null;
}
}
private SMAgentDoCommandRes DoStartCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
if (res.ResultCode == ResResultCode.NotRunning)
{
DoSogLoaderCommand(req, "start",res);
return CheckAndAckReq(req,600,res);
}
else
{
return CheckAndAckReq(req, 0,res);
}
}
private SMAgentDoCommandRes DoStopCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderCommand(req, "stop", res);
return CheckAndAckReq(req, 600, res);
}
else
{
return CheckAndAckReq(req, 0, res);
}
}
private SMAgentDoCommandRes DoHotfixCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
//运行着才能reload
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderCommand(req, "hotfix", res);
return CheckAndAckReq(req, 500, res);
}
else
{
return CheckAndAckReq(req, 0, res);
}
}
private SMAgentDoCommandRes DoReloadConfigCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
//运行着才能reload
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderCommand(req, "reloadconfig", res);
return CheckAndAckReq(req, 200, res);
}
else
{
return CheckAndAckReq(req, 0, res);
}
}
private SMAgentDoCommandRes DoReloadClusterCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
//运行着才能reload
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderCommand(req, "reloadcluster", res);
return CheckAndAckReq(req, 500, res);
}
else
{
return CheckAndAckReq(req, 0, res);
}
}
private SMAgentDoCommandRes DoUpdateAgentCommand(SMAgentDoCommandReq req)
{
var res = new SMAgentDoCommandRes();
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
res.ResultCode = ResResultCode.Success;
try
{
var procs = Process.GetProcessesByName(req.ExeFileName);
if (procs.Length > 0)
{
res.ResultCode = ResResultCode.Fail;
res.Result = "update fail, last update not finish...";
return res;
}
string curPath = System.Environment.CurrentDirectory;
SMAgentUtils.StartProcess(req.ExeFileName, curPath, "");
return res;
}
catch (Exception ex)
{
TraceLog.Exception(ex);
res.ResultCode = ResResultCode.Exception;
res.Result += "agent updater can not start... Exception:" + ex.Message;
return res;
}
}
private void CheckAgentFile(SMAgentDoCommandReq req, SMAgentDoCommandRes res)
{
try
{
string succ = "";
string fail = "";
res.ResultCode = ResResultCode.Success;
foreach (var fileAttr in req.FileList)
{
string fileFullPath = Path.Combine(fileAttr.FilePath, fileAttr.FileName);
var fileMd5 = HashHelper.MD5File(fileFullPath);
if (fileAttr.FileMd5 == fileMd5)
{
succ += string.Format("\n{0}:\t\t{1}", fileAttr.FileName, fileMd5);
}
else
{
fail += string.Format("\n{0}: center {1} \t agent {2}", fileAttr.FileName, fileAttr.FileMd5, fileMd5);
if (! string.IsNullOrEmpty(fileMd5))
{
res.ResultCode = ResResultCode.Fail;
}
}
}
if (!string.IsNullOrEmpty(succ))
{
res.Result += "\n--------------- Check Succ ---------------";
res.Result += succ;
}
if (! string.IsNullOrEmpty(fail))
{
res.Result += "\n--------------- Check Fail ---------------";
res.Result += fail;
}
}
catch (Exception e)
{
TraceLog.Exception(e);
res.ResultCode = ResResultCode.Exception;
res.Result += "\n" + e.Message;
}
}
private SMAgentDoCommandRes DoCheckAgentCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckAgentFile(req, res);
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.AddInfo = "\n\nRunning SMAgent.dll: " + HashHelper.MD5File("./SMAgent.dll") + "\t" + File.GetLastWriteTimeUtc("./SMAgent.dll");
res.HostName = SMAgentUtils.HostName;
return res;
}
private void DoSogLoaderCommand(SMAgentDoCommandReq req,string command, SMAgentDoCommandRes res)
{
if (Directory.Exists(req.WorkPath) == false)
{
res.ResultCode = ResResultCode.Exception;
res.Result += " Directory not exist (" + req.WorkPath + ")";
return;
}
string exeFullPath = req.WorkPath + "/" + req.ExeFileName;
// windows平台下如果exe文件不存在, 尝试加上".exe"后缀
if (! File.Exists(exeFullPath) && OSUtils.IsWindows() && ! exeFullPath.Contains(".exe"))
{
exeFullPath += ".exe";
if (! File.Exists(exeFullPath))
{
res.ResultCode = ResResultCode.Exception;
res.Result += " Not such file or directory(" + exeFullPath + ")";
return;
}
}
TraceLog.Trace("SMAgentCommand.DoSogLoaderCommand cmd {0} {1}", exeFullPath, req.CmdArgs);
try
{
SMAgentUtils.StartProcess(exeFullPath, req.WorkPath, req.CmdArgs);
}
catch (Exception ex)
{
TraceLog.Exception(ex);
res.ResultCode = ResResultCode.Exception;
res.Result += " " + ex.Message;
}
}
private SMAgentDoCommandRes DoCheckAgentMemCmd(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
ShareMemoryCommand shareCommand = null;
res.AddInfo = "0 KB";
try
{
shareCommand = new ShareMemoryCommand("./", SMAgentUtils.GetAppID());
bool attachSuccess = shareCommand.Attach();
if (attachSuccess == false)
{
res.ResultCode = ResResultCode.NotRunning;
return res;
}
int procId = shareCommand.ReadProcessId();
if (procId <= 0)
{
res.ResultCode = ResResultCode.NotRunning;
return res;
}
using (Process proc = Process.GetProcessById(procId))
{
if (proc == null || proc.HasExited)
{
res.ResultCode = ResResultCode.NotRunning;
return res;
}
if (proc.ProcessName != "SMAgent")
{
res.ResultCode = ResResultCode.NotRunning;
return res;
}
res.AddInfo = string.Format("{0:F} MB", proc.WorkingSet64 * 1.0 / MEM_UNIT);
res.ResultCode = ResResultCode.Success;
return res;
}
}
catch (Exception ex)
{
TraceLog.Exception(ex);
//算了,这个异常多半是GetProcessById抛出的,说明没运行
res.ResultCode = ResResultCode.NotRunning;
}
finally
{
if (shareCommand != null)
{
shareCommand.Close();
}
}
return res;
}
/// <summary>
///
/// </summary>
/// <param name="workPath"></param>
/// <param name="serverId"></param>
/// <returns>0 running,-1,notrunning ,-2 notack
///
/// </returns>
private int CheckSogLoaderIsRunning(string workPath, uint serverId, SMAgentDoCommandRes res)
{
ShareMemoryCommand shareCommand = null;
res.AddInfo = "0 KB";
try
{
string strserverId = ServerIDUtils.IDToString(serverId);
string shmFile = "sog_shf_" + strserverId;
shareCommand = new ShareMemoryCommand(workPath, serverId);
bool attachSuccess = shareCommand.Attach();
if (attachSuccess == false)
{
res.ResultCode = ResResultCode.NotRunning;
return -1;
}
int procId = shareCommand.ReadProcessId();
if(procId <= 0)
{
res.ResultCode = ResResultCode.NotRunning;
return -1;
}
using (Process proc = Process.GetProcesses().FirstOrDefault(p => p.Id == procId))
{
if (proc == null || proc.HasExited)
{
res.ResultCode = ResResultCode.NotRunning;
return -1;
}
if (proc.ProcessName != "SogLoader")
{
res.ResultCode = ResResultCode.NotRunning;
return -1;
}
res.AddInfo = string.Format("{0:F} MB", proc.WorkingSet64 * 1.0 / MEM_UNIT);
res.ResultCode = ResResultCode.Running;
return 0;
}
}
catch(Exception ex)
{
TraceLog.Exception(ex);
//算了,这个异常多半是GetProcessById抛出的,说明没运行
res.ResultCode = ResResultCode.NotRunning;
}
finally
{
if(shareCommand != null)
{
shareCommand.Close();
}
}
return -1;
}
private SMAgentDoCommandRes CheckAndAckReq(SMAgentDoCommandReq req, int firstWaitTimeMs, SMAgentDoCommandRes res)
{
TraceLog.Trace("SMAgentCommand.CheckAndAckReq begin result {0} req timeout {1}", res.ResultCode, req.StopTimeout);
bool success = false;
long startTime = SMAgentUtils.GetTimeSecond();
if (res.ResultCode == ResResultCode.NotRunning && (req.Command == "stop" || req.Command == "kill" || req.Command == "reload" || req.Command == "reloadconfig" || req.Command == "reloadcluster"))
{
success = true;
res.Result += " Dont Need or Cannot Run [" + req.Command + "], Server not Running";
}
else if(res.ResultCode == ResResultCode.Running && req.Command == "start")
{
success = true;
res.Result += " Dont Need [" + req.Command + "], Server is Running";
}
else if(res.ResultCode != ResResultCode.Exception && res.ResultCode != ResResultCode.Fail && res.ResultCode != ResResultCode.TimeOut)
{
for (int i = 0; ; i++)
{
Thread.Sleep(i == 0 ? firstWaitTimeMs : 200);
int ret = CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
if (req.Command == "stop" || req.Command == "kill")
{
if (ret == -1)
{
success = true;
break;
}
}
else if (ret == 0)
{
success = true;
break;
}
//超过10次后计算超时时间
if(i > 10 && success == false && SMAgentUtils.GetTimeSecond() > startTime + req.StopTimeout )
{
success = false;
break;
}
}
}
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.ServerIdStr = ServerIDUtils.IDToString(req.ServerId);
res.ServerType = System.Enum.GetName(typeof(ServerType), ServerIDUtils.GetServerType(req.ServerId));
res.HostName = SMAgentUtils.HostName;
if (success)
{
res.ResultCode = ResResultCode.Success;
}
else if(res.ResultCode != ResResultCode.Exception && firstWaitTimeMs > 0)
{
res.ResultCode = ResResultCode.TimeOut;
res.Result += " maybe the CMD: " + req.Command + " Because of Exception Kill then Server " + req.ServerId;
}
TraceLog.Trace("SMAgentCommand.CheckAndAckReq end result {0}", res.ResultCode);
return res;
}
private SMAgentDoCommandRes DoCheckCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
int iResult = CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
return res;
}
private void DoSogLoaderKill(string workPath, uint serverId)
{
ShareMemoryCommand shareCommand = null;
try
{
string strserverId = ServerIDUtils.IDToString(serverId);
string shmFile = "sog_shf_" + strserverId;
shareCommand = new ShareMemoryCommand(workPath, serverId);
bool attachSuccess = shareCommand.Attach();
if (attachSuccess == false)
{
return;
}
int procId = shareCommand.ReadProcessId();
if (procId <= 0)
{
return;
}
using (Process proc = Process.GetProcessById(procId))
{
if (proc == null)
{
return;
}
if (proc.ProcessName != "SogLoader")
{
return;
}
proc.Kill();
return;
}
}
catch (Exception ex)
{
TraceLog.Exception(ex);
}
finally
{
if (shareCommand != null)
{
shareCommand.Close();
}
}
return;
}
private SMAgentDoCommandRes DoKillCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
//运行着才能kill
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderKill(req.WorkPath, req.ServerId);
Thread.Sleep(10);
return CheckAndAckReq(req, 500, res);
}
else
{
return CheckAndAckReq(req, 0, res);
}
}
private SMAgentDoCommandRes DoGmCmdCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
CheckSogLoaderIsRunning(req.WorkPath, req.ServerId, res);
//运行着才能gmcmd
if (res.ResultCode == ResResultCode.Running)
{
DoSogLoaderCommand(req, "gmcmd", res);
Thread.Sleep(10);
}
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
return res;
}
private SMAgentDoCommandRes DoShellCommand(SMAgentDoCommandReq req)
{
SMShell.req = req;
string msg;
int ret = SMShell.Exec(req.CmdArgs, out msg);
if(ret == -1)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
res.ResultCode = ResResultCode.Fail;
res.Result = msg;
return res;
}
return null;
}
private SMAgentDoCommandRes DoCancelShellCommand(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
res.ResultCode = ResResultCode.Success;
try
{
SMShell.CancelShell();
}
catch (Exception ex)
{
res.ResultCode = ResResultCode.Exception;
res.Result = ex.Message;
}
return res;
}
private SMAgentDoCommandRes DoPullFileCmd(SMAgentDoCommandReq req)
{
SMAgentDoCommandRes res = new SMAgentDoCommandRes();
res.Command = req.Command;
res.SeqNum = req.SeqNum;
res.ServerId = req.ServerId;
res.HostName = SMAgentUtils.HostName;
int ret = AgentFileTransMng.Instance.DoTransCmd(req);
if (ret == 0)
{
res.ResultCode = ResResultCode.Success;
}
else
{
res.ResultCode = ResResultCode.Fail;
res.Result = AgentFileTransMng.Instance.errorMsg;
}
return res;
}
}
}