shared: add independent IPv4 and IPv6 collection [CI]
ci/woodpecker/pr/verify Pipeline was successful
ci/woodpecker/pr/web-build Pipeline was successful

This commit is contained in:
justme committed 2026-10-07 11:44:01 +08:00
1 parent c974a7dddb
commit 0eda0600cc
60 files changed
+699 -137

No files matched your search

@@ -28,8 +28,16 @@ public sealed class TestService
_time = time;
}
public async ValueTask<Result<TestRecord>> StartAsync(NodeId agentId, ProbeId probeId, StartTestRequest request, string trigger, CancellationToken ct)
public ValueTask<Result<TestRecord>> StartAsync(NodeId agentId, ProbeId probeId, StartTestRequest request, string trigger, CancellationToken ct) =>
StartAsync(agentId, probeId, request, trigger, IpVersions.V4, ct);
public async ValueTask<Result<TestRecord>> StartAsync(NodeId agentId, ProbeId probeId, StartTestRequest request, string trigger, string ipVersion, CancellationToken ct)
{
if (!IpVersions.IsValid(ipVersion))
{
return ValidationError.Fail<TestRecord>("ip_version", "must be ipv4 or ipv6");
}
PlanSpec? plan = Plans.Find(request.Plan);
if (plan is null)
{
@@ -47,6 +55,11 @@ public sealed class TestService
return Result<TestRecord>.Fail(MoShiroErrors.AgentNotActive, "agent is not active");
}
if (ipVersion == IpVersions.V6 && !agent.Ipv6Supported)
{
return Result<TestRecord>.Fail(FleetErrors.Unsupported, "this agent has not enabled IPv6 collection");
}
// Agent 在 hello 里声明了它支持的采集方法:方案里有它不支持的就不下发(否则要等到阶段开始才失败)
string? unsupported = plan.Phases.Select(p => p.Kind).FirstOrDefault(kind => !agent.Kinds.Contains(kind));
if (unsupported is not null)
@@ -65,7 +78,7 @@ public sealed class TestService
return Result<TestRecord>.Fail(MoShiroErrors.AgentOffline, "agent is offline");
}
if (!(_runtime.TryGet(agentId, out AgentRuntimeState? state) && state.IsConnected(probeId.Value)))
if (!(_runtime.TryGet(agentId, out AgentRuntimeState? state) && state.IsConnected(probeId.Value, ipVersion)))
{
return Result<TestRecord>.Fail(MoShiroErrors.ProbeOffline, $"probe {probeId.Value} has no session with this agent");
}
@@ -78,10 +91,10 @@ public sealed class TestService
var testId = new TestId(Ulid.NewPrefixed(TestId.Prefix, _time));
long now = _time.GetUtcNow().ToUnixTimeMilliseconds();
string paramsJson = request.Params is null ? "{}" : JsonSerializer.Serialize(new Dictionary<string, JsonElement>(request.Params), TestJson.Default.ParamMap);
var record = new TestRecord(testId, agentId, probeId, plan.Id, paramsJson, trigger, TestStatuses.Queued, null, null, phaseList.Count, now, null, null);
var record = new TestRecord(testId, agentId, probeId, plan.Id, paramsJson, trigger, TestStatuses.Queued, null, null, phaseList.Count, now, null, null, ipVersion);
await _tests.CreateAsync(record, ct);
Result<bool> sent = await _gateway.RunTestAsync(agentId, new TestRunParams { TestId = testId, ProbeId = probeId, Plan = plan.Id, Phases = phaseList }, ct);
Result<bool> sent = await _gateway.RunTestAsync(agentId, new TestRunParams { TestId = testId, ProbeId = probeId, IpVersion = ipVersion, Plan = plan.Id, Phases = phaseList }, ct);
if (!sent.TryGet(out _, out FleetError? sendError))
{
await _tests.UpdateStatusAsync(testId, TestStatuses.Failed, null, sendError.Code.Value, now, ct);
@@ -149,6 +162,8 @@ public sealed class TestService
public ValueTask<IReadOnlyList<TestRecord>> ListAsync(NodeId? agentId, ProbeId? probeId, int limit, CancellationToken ct) => _tests.ListAsync(agentId, probeId, limit, ct);
public ValueTask<IReadOnlyList<TestRecord>> ListAsync(NodeId? agentId, ProbeId? probeId, int limit, string? ipVersion, CancellationToken ct) => _tests.ListAsync(agentId, probeId, limit, ipVersion, ct);
public static TestResultView ToView(TestResultRecord stored)
{
StoredTestMetrics metrics = JsonSerializer.Deserialize(stored.MetricsJson, TestJson.Default.StoredTestMetrics) ?? new StoredTestMetrics();