feat: detect an agent's public IPv4 and IPv6 addresses automatically, manual values still win [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
9966ea5d63
commit
f03988d68b
26 files changed
+517
-33
No files matched your search
@@ -0,0 +1,90 @@
|
||||
using System.Net;
|
||||
using System.Text.Json.Nodes;
|
||||
using MoShiro.TestSupport;
|
||||
|
||||
namespace MoShiro.Backend.Tests;
|
||||
|
||||
/// <summary>public_host 和 ipv6_host 自动识别:Agent 上报公网地址,手填的优先,可以撤销手填。</summary>
|
||||
[Collection("probe-e2e")]
|
||||
public sealed class AddressTests
|
||||
{
|
||||
private const string V4 = "8.8.4.4";
|
||||
private const string V6 = "2606:4700:4700::1111";
|
||||
private readonly BackendFixture _backend;
|
||||
|
||||
public AddressTests(BackendFixture backend)
|
||||
{
|
||||
_backend = backend;
|
||||
}
|
||||
|
||||
private async Task<JsonNode> AgentAsync(string id) => await _backend.GetJsonAsync(_backend.Admin, "/api/admin/agents/" + id);
|
||||
|
||||
private async Task<JsonNode> PatchAsync(string id, JsonObject body)
|
||||
{
|
||||
using HttpResponseMessage response = await _backend.Admin.PatchAsync("/api/admin/agents/" + id, BackendFixture.Json(body));
|
||||
string text = await response.Content.ReadAsStringAsync();
|
||||
Assert.True(response.IsSuccessStatusCode, text);
|
||||
return JsonNode.Parse(text)!;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Hello_FillsPublicHostAndIpv6Host_PrivateAndTemporaryAddressesAreIgnored()
|
||||
{
|
||||
await using AgentSimulator agent = await _backend.ConnectAgentAsync(hello: false);
|
||||
agent.Addresses = ["10.0.0.5", "192.168.1.9", "fd00::1", "fe80::1", V6, V4];
|
||||
await agent.HelloAsync();
|
||||
|
||||
JsonNode view = null!;
|
||||
await BackendFixture.EventuallyAsync(async () => (view = await AgentAsync(agent.NodeId.Value))["ipv6_host"]!.GetValue<string>() == V6);
|
||||
Assert.Equal(V4, view["public_host"]!.GetValue<string>());
|
||||
Assert.True(view["public_host_auto"]!.GetValue<bool>());
|
||||
Assert.True(view["ipv6_host_auto"]!.GetValue<bool>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ManualValues_WinOverAutoDetection_AndCanBeRevokedBackToAuto()
|
||||
{
|
||||
await using AgentSimulator agent = await _backend.ConnectAgentAsync(hello: false);
|
||||
string id = agent.NodeId.Value;
|
||||
agent.Addresses = [V4, V6];
|
||||
await agent.HelloAsync();
|
||||
await BackendFixture.EventuallyAsync(async () => (await AgentAsync(id))["ipv6_host"]!.GetValue<string>() == V6);
|
||||
|
||||
// 手填:标记为手动,之后 Agent 再上报别的地址也不覆盖
|
||||
JsonNode manual = await PatchAsync(id, new JsonObject { ["public_host"] = "agent.example.net", ["ipv6_host"] = "" });
|
||||
Assert.False(manual["public_host_auto"]!.GetValue<bool>());
|
||||
Assert.False(manual["ipv6_host_auto"]!.GetValue<bool>());
|
||||
agent.Addresses = ["1.1.1.1", "2606:4700:4700::1001"];
|
||||
await agent.HelloAsync();
|
||||
await Task.Delay(300);
|
||||
JsonNode kept = await AgentAsync(id);
|
||||
Assert.Equal("agent.example.net", kept["public_host"]!.GetValue<string>());
|
||||
Assert.Equal("", kept["ipv6_host"]!.GetValue<string>()); // 空 = 手动关闭 IPv6
|
||||
|
||||
// 撤销手填:马上按最近一次上报的地址重新识别
|
||||
JsonNode auto = await PatchAsync(id, new JsonObject { ["public_host_auto"] = true, ["ipv6_host_auto"] = true });
|
||||
Assert.Equal("1.1.1.1", auto["public_host"]!.GetValue<string>());
|
||||
Assert.Equal("2606:4700:4700::1001", auto["ipv6_host"]!.GetValue<string>());
|
||||
Assert.True(auto["public_host_auto"]!.GetValue<bool>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AutoDetectedAddress_StaysWhileItIsStillReported_SoReorderingDoesNotFlap()
|
||||
{
|
||||
await using AgentSimulator agent = await _backend.ConnectAgentAsync(hello: false);
|
||||
string id = agent.NodeId.Value;
|
||||
agent.Addresses = [V4, "9.9.9.9"];
|
||||
await agent.HelloAsync();
|
||||
await BackendFixture.EventuallyAsync(async () => (await AgentAsync(id))["public_host"]!.GetValue<string>() == V4);
|
||||
|
||||
agent.Addresses = ["1.0.0.1", V4];
|
||||
await agent.HelloAsync();
|
||||
await Task.Delay(300);
|
||||
Assert.Equal(V4, (await AgentAsync(id))["public_host"]!.GetValue<string>());
|
||||
|
||||
// 原来的地址不见了才换
|
||||
agent.Addresses = ["1.0.0.1"];
|
||||
await agent.HelloAsync();
|
||||
await BackendFixture.EventuallyAsync(async () => (await AgentAsync(id))["public_host"]!.GetValue<string>() == "1.0.0.1");
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,10 @@ public sealed class AgentHarness : IAsyncDisposable
|
||||
Result<EnrollmentResult> enrolled = await EnrollmentClient.EnrollAsync(http, backend.BaseAddress, token, name ?? backend.UniqueName("agent"), directory, AgentApp.Version, null, TimeProvider.System, CancellationToken.None);
|
||||
Assert.True(enrolled.IsSuccess, enrolled.IsSuccess ? "" : enrolled.Error.ToString());
|
||||
|
||||
// 测试里的 Agent 只在回环上监听:手填 public_host(手动的优先于自动识别,Agent 上报本机真实地址也不会覆盖)
|
||||
using HttpResponseMessage patched = await backend.Admin.PatchAsync("/api/admin/agents/" + enrolled.Value.NodeId, BackendFixture.Json(new JsonObject { ["public_host"] = "127.0.0.1" }));
|
||||
Assert.True(patched.IsSuccessStatusCode, await patched.Content.ReadAsStringAsync());
|
||||
|
||||
var config = new AgentConfig
|
||||
{
|
||||
Fleet = { Server = backend.BaseAddress.ToString(), IdentityDir = directory },
|
||||
|
||||
@@ -139,12 +139,16 @@ public sealed class AgentSimulator : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>hello 里上报的本机公网地址(缺省不上报)。</summary>
|
||||
public string[]? Addresses { get; set; }
|
||||
|
||||
public async Task HelloAsync(string[]? kinds = null)
|
||||
{
|
||||
var meta = JsonSerializer.SerializeToElement(
|
||||
new AgentHelloMeta
|
||||
{
|
||||
TlsSpki = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)),
|
||||
Addresses = Addresses is null ? null : [.. Addresses],
|
||||
ProbeTcpPort = 7443,
|
||||
ProbeUdpPorts = [7443],
|
||||
LocalLimits = new LocalLimits { MaxTotalMbps = 200, MaxTotalPps = 20_000, MaxConcurrentTests = 1 },
|
||||
|
||||
Reference in new issue
Block a user