Linux下,需要给予可执行权限

This commit is contained in:
大石头 2023-10-21 23:19:13 +08:00
parent 96a14d7b71
commit 2a2b0bc667
5 changed files with 95 additions and 74 deletions

View File

@ -1,7 +1,4 @@
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using NewLife;
using NewLife.Log;
@ -12,41 +9,41 @@ public class ZipDeploy
{
#region
/// <summary>应用名称</summary>
public String Name { get; set; }
public String Name { get; set; } = null!;
/// <summary>文件名</summary>
public String FileName { get; set; }
public String? FileName { get; set; }
/// <summary>启动参数</summary>
public String Arguments { get; set; }
public String? Arguments { get; set; }
/// <summary>工作目录</summary>
public String WorkingDirectory { get; set; }
public String? WorkingDirectory { get; set; }
/// <summary>影子目录。应用将在其中执行</summary>
/// <remarks>默认使用上一级的shadow目录无权时使用临时目录</remarks>
public String Shadow { get; set; }
public String? Shadow { get; set; }
/// <summary>可执行文件路径</summary>
public String ExecuteFile { get; set; }
public String? ExecuteFile { get; set; }
/// <summary>用户。以该用户执行应用</summary>
public String UserName { get; set; }
public String? UserName { get; set; }
/// <summary>覆盖文件。需要拷贝覆盖已存在的文件或子目录,支持*模糊匹配,多文件分号隔开。如果目标文件不存在,配置文件等自动拷贝</summary>
public String Overwrite { get; set; }
public String? Overwrite { get; set; }
/// <summary>进程</summary>
public Process Process { get; private set; }
public Process? Process { get; private set; }
/// <summary>是否调试模式。在调试模式下,重定向控制台输出到日志</summary>
public Boolean Debug { get; set; }
/// <summary>最后的错误信息</summary>
public String LastError { get; set; }
public String? LastError { get; set; }
/// <summary>链路追踪</summary>
public ITracer Tracer { get; set; }
public ITracer? Tracer { get; set; }
#endregion
#region
@ -66,7 +63,7 @@ public class ZipDeploy
// 在参数中找到zip文件
var name = "";
var shadow = "";
var gs = new String[args.Length];
var gs = new String?[args.Length];
for (var i = 0; i < args.Length; i++)
{
if (args[i].EndsWithIgnoreCase(".zip"))
@ -238,6 +235,11 @@ public class ZipDeploy
si.FileName = "java";
si.Arguments = $"{runfile.FullName} {Arguments}";
}
else if (Runtime.Linux)
{
// Linux下需要给予可执行权限
Process.Start("chmod", $"+x {runfile.FullName}");
}
// 指定用户时,以特定用户启动进程
if (!UserName.IsNullOrEmpty())

View File

@ -123,8 +123,13 @@ public class LocalStarClient
Init();
var p = Process.GetCurrentProcess();
var fileName = p.MainModule.FileName;
var args = Environment.CommandLine.TrimStart(Path.ChangeExtension(fileName, ".dll")).Trim();
var fileName = p.MainModule?.FileName;
var args = "";
if (!fileName.IsNullOrEmpty())
{
var ext = Path.ChangeExtension(fileName, ".dll");
args = Environment.CommandLine.TrimStart(ext).Trim();
}
// 发起命令
var rs = _client.Invoke<String>("KillAndStart", new
@ -148,7 +153,7 @@ public class LocalStarClient
/// <param name="url">zip包下载源</param>
/// <param name="version">版本号</param>
/// <param name="target">目标目录</param>
public Boolean ProbeAndInstall(String url = null, String version = null, String target = null)
public Boolean ProbeAndInstall(String? url = null, String? version = null, String? target = null)
{
//if (url.IsNullOrEmpty()) throw new ArgumentNullException(nameof(url));
if (url.IsNullOrEmpty())
@ -183,7 +188,7 @@ public class LocalStarClient
}
catch (Exception ex)
{
WriteLog("没有探测到StarAgent{0}", ex.GetTrue().Message);
WriteLog("没有探测到StarAgent{0}", ex.GetTrue()?.Message);
}
if (target.IsNullOrEmpty())
@ -194,12 +199,12 @@ public class LocalStarClient
{
try
{
target = Path.GetDirectoryName(p.MainModule.FileName);
}
catch
{
target = Path.GetDirectoryName(p.MainWindowTitle);
if (p.MainModule != null)
target = Path.GetDirectoryName(p.MainModule.FileName);
}
catch { }
if (target.IsNullOrEmpty()) target = Path.GetDirectoryName(p.MainWindowTitle);
WriteLog("发现进程StarAgentProcessId={0}target={1}", p.Id, target);
}
@ -255,7 +260,7 @@ public class LocalStarClient
}
var fileName = info?.FileName;
if (!fileName.IsNullOrEmpty() && Path.GetFullPath(fileName).EqualIgnoreCase("dotnet.exe")) fileName = info.Arguments;
if (!fileName.IsNullOrEmpty() && Path.GetFullPath(fileName).EqualIgnoreCase("dotnet.exe")) fileName = info?.Arguments;
var rs = false;
if (Runtime.Windows)
@ -269,7 +274,7 @@ public class LocalStarClient
return true;
}
private Boolean RunAgentOnWindows(String fileName, String target, Boolean inService)
private Boolean RunAgentOnWindows(String? fileName, String target, Boolean inService)
{
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.exe").GetFullPath();
@ -293,13 +298,13 @@ public class LocalStarClient
};
var p = Process.Start(si);
WriteLog("启动进程成功 pid={0}", p.Id);
WriteLog("启动进程成功 pid={0}", p?.Id);
}
return true;
}
private Boolean RunAgentOnLinux(String fileName, String target, Boolean inService)
private Boolean RunAgentOnLinux(String? fileName, String target, Boolean inService)
{
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent").GetFullPath();
@ -326,13 +331,13 @@ public class LocalStarClient
};
var p = Process.Start(si);
WriteLog("启动进程成功 pid={0}", p.Id);
WriteLog("启动进程成功 pid={0}", p?.Id);
}
return true;
}
private Boolean RunAgentOnDotnet(String fileName, String target, Boolean inService)
private Boolean RunAgentOnDotnet(String? fileName, String target, Boolean inService)
{
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.dll").GetFullPath();
if (!File.Exists(fileName)) return false;
@ -355,7 +360,7 @@ public class LocalStarClient
};
var p = Process.Start(si);
WriteLog("启动进程成功 pid={0}", p.Id);
WriteLog("启动进程成功 pid={0}", p?.Id);
}
return true;
@ -423,7 +428,7 @@ public class LocalStarClient
/// <param name="local">本地信息,用于告知对方我是谁</param>
/// <param name="timeout"></param>
/// <returns></returns>
public static IEnumerable<AgentInfo> Scan(AgentInfo local = null, Int32 timeout = 15_000)
public static IEnumerable<AgentInfo> Scan(AgentInfo? local = null, Int32 timeout = 15_000)
{
var encoder = new JsonEncoder { Log = XTrace.Log };
// 构造请求消息
@ -438,7 +443,8 @@ public class LocalStarClient
//};
//var buf = msg.ToPacket().ToArray();
var buf = encoder.CreateRequest("Info", null).ToPacket().ToArray();
var buf = encoder.CreateRequest("Info", null).ToPacket()?.ToArray();
if (buf == null) yield break;
// 在局域网中广播消息
var udp = new UdpClient();
@ -448,7 +454,7 @@ public class LocalStarClient
while (DateTime.Now < end)
{
var rs = new DefaultMessage();
IPEndPoint ep = null;
IPEndPoint? ep = null;
buf = udp.Receive(ref ep);
if (buf != null && rs.Read(buf))
{
@ -467,7 +473,7 @@ public class LocalStarClient
#region
/// <summary>日志</summary>
public ILog Log { get; set; }
public ILog Log { get; set; } = Logger.Null;
/// <summary>写日志</summary>
/// <param name="format"></param>

View File

@ -4,13 +4,13 @@
public class ProcessInfo
{
/// <summary>名称</summary>
public String Name { get; set; }
public String Name { get; set; } = null!;
/// <summary>进程Id</summary>
public Int32 ProcessId { get; set; }
/// <summary>进程名</summary>
public String ProcessName { get; set; }
public String? ProcessName { get; set; }
/// <summary>创建时间</summary>
public DateTime CreateTime { get; set; }

View File

@ -23,22 +23,22 @@ internal class ServiceController : DisposeBase
public Int32 Id => _id;
/// <summary>服务名</summary>
public String Name { get; set; }
public String Name { get; set; } = null!;
/// <summary>进程ID</summary>
public Int32 ProcessId { get; set; }
/// <summary>进程名</summary>
public String ProcessName { get; set; }
public String? ProcessName { get; set; }
/// <summary>服务信息</summary>
public ServiceInfo Info { get; private set; }
public ServiceInfo? Info { get; private set; }
/// <summary>部署信息</summary>
public DeployInfo DeployInfo { get; set; }
public DeployInfo? DeployInfo { get; set; }
/// <summary>进程</summary>
public Process Process { get; set; }
public Process? Process { get; set; }
/// <summary>是否正在工作</summary>
public Boolean Running { get; set; }
@ -59,13 +59,13 @@ internal class ServiceController : DisposeBase
public Int32 MaxFails { get; set; } = 20;
/// <summary>事件客户端</summary>
public IEventProvider EventProvider { get; set; }
public IEventProvider? EventProvider { get; set; }
private String _fileName;
private String _workdir;
private TimerX _timer;
private String? _fileName;
private String? _workdir;
private TimerX? _timer;
private Int32 _error;
private AppInfo _appInfo;
private AppInfo? _appInfo;
#endregion
#region
@ -114,8 +114,14 @@ internal class ServiceController : DisposeBase
if (file.Contains('/') || file.Contains('\\'))
{
file = file.GetFullPath();
if (workDir.IsNullOrEmpty()) workDir = Path.GetDirectoryName(file);
}
if (workDir.IsNullOrEmpty()) workDir = Path.GetDirectoryName(file);
if (workDir.IsNullOrEmpty())
{
WriteLog("应用[{0}]工作目录为空", Name);
return false;
}
workDir = workDir.GetFullPath();
_fileName = null;
_workdir = workDir;
@ -128,7 +134,7 @@ internal class ServiceController : DisposeBase
using var span = Tracer?.NewSpan("StartService", service);
try
{
Process p;
Process? p;
var isZip = src.EndsWithIgnoreCase(".zip");
// 在环境变量中设置BasePath不用担心影响当前进程因为PathHelper仅读取一次
@ -212,7 +218,7 @@ internal class ServiceController : DisposeBase
}
}
public ZipDeploy Extract(String file, String args, String workDir, Boolean needRun)
public ZipDeploy? Extract(String file, String? args, String workDir, Boolean needRun)
{
var isZip = file.EqualIgnoreCase("ZipDeploy") || file.EndsWithIgnoreCase(".zip");
if (!isZip) return null;
@ -246,7 +252,7 @@ internal class ServiceController : DisposeBase
return deploy;
}
private Process RunZip(String file, String args, String workDir, ServiceInfo service)
private Process? RunZip(String file, String? args, String workDir, ServiceInfo service)
{
var deploy = new ZipDeploy
{
@ -279,7 +285,7 @@ internal class ServiceController : DisposeBase
return deploy.Process;
}
private Process RunExe(String file, String args, String workDir, ServiceInfo service)
private Process? RunExe(String file, String? args, String workDir, ServiceInfo service)
{
//WriteLog("拉起进程:{0} {1}", file, args);
@ -300,6 +306,12 @@ internal class ServiceController : DisposeBase
UseShellExecute = false,
};
if (Runtime.Linux)
{
// Linux下需要给予可执行权限
Process.Start("chmod", $"+x {fileName}");
}
// 指定用户时,以特定用户启动进程
if (!service.UserName.IsNullOrEmpty())
{
@ -336,7 +348,7 @@ internal class ServiceController : DisposeBase
WriteLog("启动用户:{0}", si.UserName);
var p = Process.Start(si);
if (StartWait > 0 && p.WaitForExit(StartWait) && p.ExitCode != 0)
if (StartWait > 0 && p != null && p.WaitForExit(StartWait) && p.ExitCode != 0)
{
WriteLog("启动失败ExitCode={0}", p.ExitCode);
@ -369,7 +381,7 @@ internal class ServiceController : DisposeBase
WriteLog("停止应用 PID={0}/{1} 原因:{2}", p.Id, p.ProcessName, reason);
using var span = Tracer?.NewSpan("StopService", $"{Info.Name} reason={reason}");
using var span = Tracer?.NewSpan("StopService", $"{Info?.Name} reason={reason}");
_timer.TryDispose();
_timer = null;
@ -447,7 +459,8 @@ internal class ServiceController : DisposeBase
/// <returns>本次是否成功启动或接管原来已启动返回false</returns>
public Boolean Check()
{
using var span = Tracer?.NewSpan("CheckService", Info.Name);
var inf = Info ?? new ServiceInfo();
using var span = Tracer?.NewSpan("CheckService", inf.Name);
// 获取当前进程Id
var mypid = Process.GetCurrentProcess().Id;
@ -464,12 +477,12 @@ internal class ServiceController : DisposeBase
_error = 0;
// 检查内存限制
if (Info.MaxMemory <= 0) return false;
if (inf.MaxMemory <= 0) return false;
var mem = p.WorkingSet64 / 1024 / 1024;
if (mem <= Info.MaxMemory) return true;
if (mem <= inf.MaxMemory) return true;
WriteLog("内存超限!{0}>{1}", mem, Info.MaxMemory);
WriteLog("内存超限!{0}>{1}", mem, inf.MaxMemory);
Stop("内存超限");
}
@ -525,14 +538,14 @@ internal class ServiceController : DisposeBase
}
// 进程不存在,但名称存在
if (p == null && !ProcessName.IsNullOrEmpty() && Info.Mode != ServiceModes.Multiple)
if (p == null && !ProcessName.IsNullOrEmpty() && inf.Mode != ServiceModes.Multiple)
{
if (ProcessName.EqualIgnoreCase("dotnet", "java"))
{
var target = _fileName ?? Info.FileName;
var target = _fileName ?? inf.FileName;
if (target.EqualIgnoreCase("dotnet", "java"))
{
var ss = Info.Arguments.Split(' ');
var ss = inf.Arguments?.Split(' ');
if (ss != null) target = ss.FirstOrDefault(e => e.EndsWithIgnoreCase(".dll", ".jar"));
}
if (!target.IsNullOrEmpty())
@ -575,7 +588,7 @@ internal class ServiceController : DisposeBase
if (p != null && EventProvider is StarClient client)
{
if (_appInfo == null)
_appInfo = new AppInfo(p) { AppName = Info.Name };
_appInfo = new AppInfo(p) { AppName = inf.Name };
else
_appInfo.Refresh();
@ -601,7 +614,7 @@ internal class ServiceController : DisposeBase
return true;
}
public void SetProcess(Process process)
public void SetProcess(Process? process)
{
Process = process;
if (process != null)
@ -643,7 +656,7 @@ internal class ServiceController : DisposeBase
private Boolean _ready;
private DateTime _readyTime;
private void MonitorFileChange(Object state)
private void MonitorFileChange(Object? state)
{
var first = _files.Count == 0;
var changed = "";
@ -711,15 +724,15 @@ internal class ServiceController : DisposeBase
#region
/// <summary>性能追踪</summary>
public ITracer Tracer { get; set; }
public ITracer? Tracer { get; set; }
/// <summary>日志</summary>
public ILog Log { get; set; }
public ILog Log { get; set; } = Logger.Null;
/// <summary>写日志</summary>
/// <param name="format"></param>
/// <param name="args"></param>
public void WriteLog(String format, params Object[] args)
public void WriteLog(String format, params Object?[] args)
{
Log?.Info($"[{Id}/{Name}]{format}", args);

View File

@ -14,22 +14,22 @@ public class Upgrade
{
#region
/// <summary>名称</summary>
public String Name { get; set; }
public String Name { get; set; } = null!;
/// <summary>更新目录。默认./Update</summary>
public String UpdatePath { get; set; } = "Update";
public String? UpdatePath { get; set; } = "Update";
/// <summary>目标目录</summary>
public String DestinationPath { get; set; } = ".";
public String? DestinationPath { get; set; } = ".";
/// <summary>源文件下载地址</summary>
public String Url { get; set; }
public String? Url { get; set; }
/// <summary>更新源文件</summary>
public String SourceFile { get; set; }
public String? SourceFile { get; set; }
/// <summary>解压缩的临时目录</summary>
public String TempPath { get; set; }
public String? TempPath { get; set; }
#endregion
#region
@ -303,7 +303,7 @@ public class Upgrade
#endregion
#region
private HttpClient _Client;
private HttpClient? _Client;
private HttpClient CreateClient()
{
if (_Client != null) return _Client;