77 lines
2.7 KiB
C#
77 lines
2.7 KiB
C#
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using Fleet.Core;
|
|
using Fleet.Hosting;
|
|
using MoShiro.Measurement;
|
|
using MoShiro.Protocol;
|
|
|
|
namespace MoShiro.Agent;
|
|
|
|
/// <summary>
|
|
/// Native supervisor bridge: writes only fixed wake-up flags and a health beacon in tmpfs.
|
|
/// Never downloads, installs, verifies releases, or executes commands. The root-owned host
|
|
/// updater independently fetches and verifies its locally configured release feed.
|
|
/// </summary>
|
|
public sealed class OpenWrtUpdater
|
|
{
|
|
private readonly ConfigStore _runtime;
|
|
private readonly string _statusPath;
|
|
private readonly TimeProvider _time;
|
|
private readonly INodeLog _log;
|
|
|
|
public OpenWrtUpdater(string runtimeDirectory, string statusPath, TimeProvider time, INodeLog log)
|
|
{
|
|
_runtime = new ConfigStore(runtimeDirectory);
|
|
_statusPath = statusPath;
|
|
_time = time;
|
|
_log = log;
|
|
}
|
|
|
|
public static OpenWrtUpdater? FromEnvironment(TimeProvider time, INodeLog log) =>
|
|
Environment.GetEnvironmentVariable(RestartUpdater.EnvironmentVariable) == "openwrt"
|
|
? new OpenWrtUpdater("/var/run/moshiro-agent", "/var/run/moshiro-update/status.json", time, log)
|
|
: null;
|
|
|
|
public void Offer() => Signal("check.request");
|
|
|
|
public void RequestApply() => Signal("apply.request");
|
|
|
|
private void Signal(string fileName)
|
|
{
|
|
try
|
|
{
|
|
_runtime.Write(fileName, "check"u8.ToArray());
|
|
}
|
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
|
{
|
|
_log.Warn("could not signal the native updater", ("err", ex.Message));
|
|
}
|
|
}
|
|
|
|
/// <summary>Called by the Fleet heartbeat: evidence that this version reached Backend.</summary>
|
|
public UpdateStatus? Status()
|
|
{
|
|
try
|
|
{
|
|
var health = new OpenWrtHealth(BuildInfo.Version, Environment.ProcessId, _time.GetUtcNow().ToUnixTimeSeconds());
|
|
_runtime.Write("health.json", JsonSerializer.SerializeToUtf8Bytes(health, AgentConfigContext.Default.OpenWrtHealth));
|
|
if (!File.Exists(_statusPath) || new FileInfo(_statusPath).Length > 8192)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return JsonSerializer.Deserialize(File.ReadAllBytes(_statusPath), MoShiroJsonContext.Default.UpdateStatus);
|
|
}
|
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or JsonException)
|
|
{
|
|
_log.Warn("could not read native update status", ("err", ex.Message));
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed record OpenWrtHealth(
|
|
[property: JsonPropertyName("version")] string Version,
|
|
[property: JsonPropertyName("pid")] int Pid,
|
|
[property: JsonPropertyName("at")] long At);
|