feat: node updates by restart, auto by default; Podman Quadlet install from the panel alongside compose [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful
ci/woodpecker/push/main-amd64-build Pipeline was successful
This commit is contained in:
1 parent
88b1a0a9bb
commit
535bb3517d
32 files changed
+751
-152
No files matched your search
@@ -94,6 +94,53 @@ public sealed class InstallTests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("agent")]
|
||||
[InlineData("probe")]
|
||||
public async Task QuadletInstall_ChecksTheUnitHash_PointsTheImageAtTheConfiguredRepository_AndLeavesAutoUpdateOn(string role)
|
||||
{
|
||||
JsonNode created = await CreateAsync(role);
|
||||
JsonNode quadlet = created["quadlet"]!;
|
||||
string env = quadlet["env"]!.GetValue<string>();
|
||||
string command = quadlet["command"]!.GetValue<string>();
|
||||
string url = quadlet["url"]!.GetValue<string>();
|
||||
|
||||
Assert.EndsWith($"/install/quadlet/{role}.container", url, StringComparison.Ordinal);
|
||||
Assert.Contains($"MOSHIRO_JOIN={created["plaintext"]!.GetValue<string>()}", env, StringComparison.Ordinal);
|
||||
Assert.Contains("# MOSHIRO_UPDATE_POLICY=manual", env, StringComparison.Ordinal); // 默认自动更新,env 里只留一行注释说明怎么改成手动
|
||||
Assert.DoesNotContain("\nMOSHIRO_UPDATE_POLICY=", env, StringComparison.Ordinal);
|
||||
Assert.Contains($"~/.config/moshiro/{role}.env", command, StringComparison.Ordinal);
|
||||
Assert.Contains("chmod 600", command, StringComparison.Ordinal);
|
||||
Assert.Contains($"echo \"{quadlet["sha256"]!.GetValue<string>()} $HOME/.config/containers/systemd/moshiro-{role}.container\" | sha256sum -c -", command, StringComparison.Ordinal);
|
||||
Assert.Contains($"Image=", command, StringComparison.Ordinal);
|
||||
Assert.Contains($"/moshiro-{role}:latest", command, StringComparison.Ordinal);
|
||||
Assert.EndsWith($"systemctl --user daemon-reload && systemctl --user start moshiro-{role}", command, StringComparison.Ordinal);
|
||||
|
||||
// 面板提供的就是命令里核对的那份:Pull=always(退出再被拉起就是更新),并告诉节点外面会重新拉取
|
||||
using HttpResponseMessage served = await _backend.Anonymous.GetAsync($"/install/quadlet/{role}.container");
|
||||
Assert.Equal(HttpStatusCode.OK, served.StatusCode);
|
||||
byte[] body = await served.Content.ReadAsByteArrayAsync();
|
||||
Assert.Equal(quadlet["sha256"]!.GetValue<string>(), Convert.ToHexStringLower(System.Security.Cryptography.SHA256.HashData(body)));
|
||||
string unit = System.Text.Encoding.UTF8.GetString(body);
|
||||
Assert.Contains("\nPull=always", unit, StringComparison.Ordinal);
|
||||
Assert.Contains("Environment=MOSHIRO_UPDATE=restart", unit, StringComparison.Ordinal);
|
||||
Assert.Contains("ReadOnly=true", unit, StringComparison.Ordinal);
|
||||
Assert.Contains("DropCapability=ALL", unit, StringComparison.Ordinal);
|
||||
Assert.Contains("NoNewPrivileges=true", unit, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("jt_", unit, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("evil.container")]
|
||||
[InlineData("backend.container")]
|
||||
[InlineData("agent")]
|
||||
public async Task OnlyTheTwoQuadletUnits_AreServed(string file)
|
||||
{
|
||||
using HttpResponseMessage response = await _backend.Anonymous.GetAsync("/install/quadlet/" + file);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("agent.yaml")]
|
||||
[InlineData("probe.yaml")]
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed partial class OpenApiConformanceTests
|
||||
foreach ((string path, _) in doc["paths"]!.AsObject())
|
||||
{
|
||||
string[] prefixes = ["/api/public/", "/api/admin/", "/api/agent/v1/"];
|
||||
string[] roots = ["/healthz", "/metrics", "/install", "/install.ps1", "/install/manifest", "/install/manifest.sig", "/install/compose/{file}", "/api/release/offer"];
|
||||
string[] roots = ["/healthz", "/metrics", "/install", "/install.ps1", "/install/manifest", "/install/manifest.sig", "/install/compose/{file}", "/install/quadlet/{file}", "/api/release/offer"];
|
||||
Assert.True(prefixes.Any(p => path.StartsWith(p, StringComparison.Ordinal)) || roots.Contains(path), $"{path} is outside the documented layers");
|
||||
foreach (string segment in path.Split('/', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user