save progress
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Zastava.Agent.Configuration;
|
||||
using StellaOps.Zastava.Core.Contracts;
|
||||
|
||||
@@ -34,15 +35,18 @@ internal sealed class RuntimeEventsClient : IRuntimeEventsClient
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IOptionsMonitor<ZastavaAgentOptions> _options;
|
||||
private readonly ILogger<RuntimeEventsClient> _logger;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public RuntimeEventsClient(
|
||||
HttpClient httpClient,
|
||||
IOptionsMonitor<ZastavaAgentOptions> options,
|
||||
ILogger<RuntimeEventsClient> logger)
|
||||
ILogger<RuntimeEventsClient> logger,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_guidProvider = guidProvider ?? new SystemGuidProvider();
|
||||
}
|
||||
|
||||
public async Task<RuntimeEventsSubmitResult> SubmitAsync(
|
||||
@@ -63,7 +67,7 @@ internal sealed class RuntimeEventsClient : IRuntimeEventsClient
|
||||
{
|
||||
var request = new RuntimeEventsSubmitRequest
|
||||
{
|
||||
BatchId = Guid.NewGuid().ToString("N"),
|
||||
BatchId = _guidProvider.NewGuid().ToString("N"),
|
||||
Events = envelopes.ToArray()
|
||||
};
|
||||
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Env/StellaOps.Scanner.Surface.Env.csproj" />
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Secrets/StellaOps.Scanner.Surface.Secrets.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Cryptography.DependencyInjection/StellaOps.Cryptography.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Determinism.Abstractions/StellaOps.Determinism.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text.Json;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Zastava.Agent.Configuration;
|
||||
using StellaOps.Zastava.Agent.Docker;
|
||||
|
||||
@@ -22,16 +23,22 @@ internal sealed class HealthCheckHostedService : BackgroundService
|
||||
private readonly IDockerSocketClient _dockerClient;
|
||||
private readonly IOptionsMonitor<ZastavaAgentOptions> _options;
|
||||
private readonly ILogger<HealthCheckHostedService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
private HttpListener? _listener;
|
||||
|
||||
public HealthCheckHostedService(
|
||||
IDockerSocketClient dockerClient,
|
||||
IOptionsMonitor<ZastavaAgentOptions> options,
|
||||
ILogger<HealthCheckHostedService> logger)
|
||||
ILogger<HealthCheckHostedService> logger,
|
||||
TimeProvider? timeProvider = null,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_dockerClient = dockerClient ?? throw new ArgumentNullException(nameof(dockerClient));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? new SystemGuidProvider();
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
@@ -184,7 +191,7 @@ internal sealed class HealthCheckHostedService : BackgroundService
|
||||
{
|
||||
Status = overallHealthy ? "healthy" : "unhealthy",
|
||||
Checks = checks,
|
||||
Timestamp = DateTimeOffset.UtcNow
|
||||
Timestamp = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
return (overallHealthy ? 200 : 503, response);
|
||||
@@ -203,7 +210,7 @@ internal sealed class HealthCheckHostedService : BackgroundService
|
||||
{
|
||||
Status = "ready",
|
||||
Message = "Agent ready to process container events",
|
||||
Timestamp = DateTimeOffset.UtcNow
|
||||
Timestamp = _timeProvider.GetUtcNow()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -211,7 +218,7 @@ internal sealed class HealthCheckHostedService : BackgroundService
|
||||
{
|
||||
Status = "not_ready",
|
||||
Message = "Docker daemon not reachable",
|
||||
Timestamp = DateTimeOffset.UtcNow
|
||||
Timestamp = _timeProvider.GetUtcNow()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -220,16 +227,16 @@ internal sealed class HealthCheckHostedService : BackgroundService
|
||||
{
|
||||
Status = "not_ready",
|
||||
Message = $"Ready check failed: {ex.Message}",
|
||||
Timestamp = DateTimeOffset.UtcNow
|
||||
Timestamp = _timeProvider.GetUtcNow()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDirectoryWritable(string path)
|
||||
private bool IsDirectoryWritable(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var testFile = Path.Combine(path, $".healthcheck-{Guid.NewGuid():N}");
|
||||
var testFile = Path.Combine(path, $".healthcheck-{_guidProvider.NewGuid():N}");
|
||||
File.WriteAllText(testFile, "test");
|
||||
File.Delete(testFile);
|
||||
return true;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Threading.Channels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Zastava.Agent.Configuration;
|
||||
using StellaOps.Zastava.Core.Contracts;
|
||||
using StellaOps.Zastava.Core.Serialization;
|
||||
@@ -31,6 +32,7 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
private readonly string _spoolPath;
|
||||
private readonly ILogger<RuntimeEventBuffer> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
private readonly long _maxDiskBytes;
|
||||
private readonly int _capacity;
|
||||
|
||||
@@ -39,11 +41,13 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
public RuntimeEventBuffer(
|
||||
IOptions<ZastavaAgentOptions> agentOptions,
|
||||
TimeProvider timeProvider,
|
||||
ILogger<RuntimeEventBuffer> logger)
|
||||
ILogger<RuntimeEventBuffer> logger,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(agentOptions);
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_guidProvider = guidProvider ?? new SystemGuidProvider();
|
||||
|
||||
var options = agentOptions.Value ?? throw new ArgumentNullException(nameof(agentOptions));
|
||||
|
||||
@@ -178,7 +182,7 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
private async Task<string> PersistAsync(byte[] payload, CancellationToken cancellationToken)
|
||||
{
|
||||
var timestamp = _timeProvider.GetUtcNow().UtcTicks;
|
||||
var fileName = $"{timestamp:D20}-{Guid.NewGuid():N}{FileExtension}";
|
||||
var fileName = $"{timestamp:D20}-{_guidProvider.NewGuid():N}{FileExtension}";
|
||||
var filePath = Path.Combine(_spoolPath, fileName);
|
||||
|
||||
Directory.CreateDirectory(_spoolPath);
|
||||
|
||||
@@ -16,18 +16,21 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
private readonly IRuntimeEventsClient _eventsClient;
|
||||
private readonly IOptionsMonitor<ZastavaAgentOptions> _options;
|
||||
private readonly ILogger<RuntimeEventDispatchService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly Random _jitterRandom = new();
|
||||
|
||||
public RuntimeEventDispatchService(
|
||||
IRuntimeEventBuffer eventBuffer,
|
||||
IRuntimeEventsClient eventsClient,
|
||||
IOptionsMonitor<ZastavaAgentOptions> options,
|
||||
ILogger<RuntimeEventDispatchService> logger)
|
||||
ILogger<RuntimeEventDispatchService> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_eventBuffer = eventBuffer ?? throw new ArgumentNullException(nameof(eventBuffer));
|
||||
_eventsClient = eventsClient ?? throw new ArgumentNullException(nameof(eventsClient));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
@@ -43,7 +46,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
flushInterval);
|
||||
|
||||
var batch = new List<RuntimeEventBufferItem>(batchSize);
|
||||
var lastFlush = DateTimeOffset.UtcNow;
|
||||
var lastFlush = _timeProvider.GetUtcNow();
|
||||
var failureCount = 0;
|
||||
|
||||
try
|
||||
@@ -53,7 +56,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
batch.Add(item);
|
||||
|
||||
var shouldFlush = batch.Count >= batchSize ||
|
||||
(batch.Count > 0 && DateTimeOffset.UtcNow - lastFlush >= flushInterval);
|
||||
(batch.Count > 0 && _timeProvider.GetUtcNow() - lastFlush >= flushInterval);
|
||||
|
||||
if (shouldFlush)
|
||||
{
|
||||
@@ -68,7 +71,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
}
|
||||
|
||||
batch.Clear();
|
||||
lastFlush = DateTimeOffset.UtcNow;
|
||||
lastFlush = _timeProvider.GetUtcNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class EbpfProbeManager : IProbeManager, IAsyncDisposable
|
||||
private readonly IRuntimeSignalCollector _signalCollector;
|
||||
private readonly ISignalPublisher _signalPublisher;
|
||||
private readonly EbpfProbeManagerOptions _options;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ConcurrentDictionary<string, SignalCollectionHandle> _activeHandles;
|
||||
private bool _disposed;
|
||||
|
||||
@@ -30,12 +31,14 @@ public sealed class EbpfProbeManager : IProbeManager, IAsyncDisposable
|
||||
ILogger<EbpfProbeManager> logger,
|
||||
IRuntimeSignalCollector signalCollector,
|
||||
ISignalPublisher signalPublisher,
|
||||
IOptions<EbpfProbeManagerOptions> options)
|
||||
IOptions<EbpfProbeManagerOptions> options,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_logger = logger;
|
||||
_signalCollector = signalCollector;
|
||||
_signalPublisher = signalPublisher;
|
||||
_options = options.Value;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_activeHandles = new ConcurrentDictionary<string, SignalCollectionHandle>();
|
||||
}
|
||||
|
||||
@@ -277,7 +280,7 @@ public sealed class EbpfProbeManager : IProbeManager, IAsyncDisposable
|
||||
Namespace = evt.Labels.GetValueOrDefault("io.kubernetes.pod.namespace"),
|
||||
PodName = evt.Labels.GetValueOrDefault("io.kubernetes.pod.name"),
|
||||
Summary = summary,
|
||||
CollectedAt = DateTimeOffset.UtcNow,
|
||||
CollectedAt = _timeProvider.GetUtcNow(),
|
||||
};
|
||||
|
||||
await _signalPublisher.PublishAsync(message, ct);
|
||||
|
||||
@@ -30,10 +30,12 @@ internal sealed class ProcSnapshotCollector : IProcSnapshotCollector
|
||||
private readonly DotNetAssemblyCollector _dotnetCollector;
|
||||
private readonly PhpAutoloadCollector _phpCollector;
|
||||
private readonly ILogger<ProcSnapshotCollector> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly string _procRoot;
|
||||
|
||||
public ProcSnapshotCollector(
|
||||
IOptions<ZastavaObserverOptions> options,
|
||||
TimeProvider? timeProvider,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
@@ -41,6 +43,7 @@ internal sealed class ProcSnapshotCollector : IProcSnapshotCollector
|
||||
|
||||
_procRoot = options.Value.ProcRootPath;
|
||||
_logger = loggerFactory.CreateLogger<ProcSnapshotCollector>();
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
|
||||
_javaCollector = new JavaClasspathCollector(
|
||||
_procRoot,
|
||||
@@ -82,7 +85,7 @@ internal sealed class ProcSnapshotCollector : IProcSnapshotCollector
|
||||
|
||||
var document = new ProcSnapshotDocument
|
||||
{
|
||||
Id = $"{tenant}:{imageDigest}:{pid}:{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}",
|
||||
Id = $"{tenant}:{imageDigest}:{pid}:{_timeProvider.GetUtcNow().ToUnixTimeMilliseconds()}",
|
||||
Tenant = tenant,
|
||||
ImageDigest = imageDigest,
|
||||
ContainerId = container.Id,
|
||||
@@ -91,7 +94,7 @@ internal sealed class ProcSnapshotCollector : IProcSnapshotCollector
|
||||
Classpath = snapshot.Classpath,
|
||||
LoadedAssemblies = snapshot.LoadedAssemblies,
|
||||
AutoloadPaths = snapshot.AutoloadPaths,
|
||||
CapturedAt = DateTimeOffset.UtcNow
|
||||
CapturedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
_logger.LogDebug(
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Threading.Channels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Zastava.Core.Contracts;
|
||||
using StellaOps.Zastava.Core.Serialization;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
@@ -32,6 +33,7 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
private readonly string spoolPath;
|
||||
private readonly ILogger<RuntimeEventBuffer> logger;
|
||||
private readonly TimeProvider timeProvider;
|
||||
private readonly IGuidProvider guidProvider;
|
||||
private readonly long maxDiskBytes;
|
||||
|
||||
private long currentBytes;
|
||||
@@ -40,11 +42,13 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
public RuntimeEventBuffer(
|
||||
IOptions<ZastavaObserverOptions> observerOptions,
|
||||
TimeProvider timeProvider,
|
||||
ILogger<RuntimeEventBuffer> logger)
|
||||
ILogger<RuntimeEventBuffer> logger,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(observerOptions);
|
||||
this.timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
|
||||
var options = observerOptions.Value ?? throw new ArgumentNullException(nameof(observerOptions));
|
||||
|
||||
@@ -178,7 +182,7 @@ internal sealed class RuntimeEventBuffer : IRuntimeEventBuffer
|
||||
private async Task<string> PersistAsync(byte[] payload, CancellationToken cancellationToken)
|
||||
{
|
||||
var timestamp = timeProvider.GetUtcNow().UtcTicks;
|
||||
var fileName = $"{timestamp:D20}-{Guid.NewGuid():N}{FileExtension}";
|
||||
var fileName = $"{timestamp:D20}-{guidProvider.NewGuid():N}{FileExtension}";
|
||||
var filePath = Path.Combine(spoolPath, fileName);
|
||||
|
||||
Directory.CreateDirectory(spoolPath);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Secrets/StellaOps.Scanner.Surface.Secrets.csproj" />
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Validation/StellaOps.Scanner.Surface.Validation.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Cryptography.DependencyInjection/StellaOps.Cryptography.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Determinism.Abstractions/StellaOps.Determinism.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos/runtime/v1/runtime.proto" GrpcServices="Client" />
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Net;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Zastava.Core.Contracts;
|
||||
using StellaOps.Zastava.Observer.Backend;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
@@ -17,6 +18,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
private readonly IRuntimeFactsClient runtimeFactsClient;
|
||||
private readonly IOptionsMonitor<ZastavaObserverOptions> observerOptions;
|
||||
private readonly TimeProvider timeProvider;
|
||||
private readonly IGuidProvider guidProvider;
|
||||
private readonly ILogger<RuntimeEventDispatchService> logger;
|
||||
|
||||
public RuntimeEventDispatchService(
|
||||
@@ -25,6 +27,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
IRuntimeFactsClient runtimeFactsClient,
|
||||
IOptionsMonitor<ZastavaObserverOptions> observerOptions,
|
||||
TimeProvider timeProvider,
|
||||
IGuidProvider? guidProvider,
|
||||
ILogger<RuntimeEventDispatchService> logger)
|
||||
{
|
||||
this.buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));
|
||||
@@ -32,6 +35,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
this.runtimeFactsClient = runtimeFactsClient ?? throw new ArgumentNullException(nameof(runtimeFactsClient));
|
||||
this.observerOptions = observerOptions ?? throw new ArgumentNullException(nameof(observerOptions));
|
||||
this.timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
this.guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -127,7 +131,7 @@ internal sealed class RuntimeEventDispatchService : BackgroundService
|
||||
|
||||
var request = new RuntimeEventsIngestRequest
|
||||
{
|
||||
BatchId = $"obs-{timeProvider.GetUtcNow():yyyyMMddTHHmmssfff}-{Guid.NewGuid():N}",
|
||||
BatchId = $"obs-{timeProvider.GetUtcNow():yyyyMMddTHHmmssfff}-{guidProvider.NewGuid():N}",
|
||||
Events = envelopes
|
||||
};
|
||||
|
||||
|
||||
@@ -6,14 +6,17 @@ public sealed class WebhookCertificateHealthCheck : IHealthCheck
|
||||
{
|
||||
private readonly IWebhookCertificateProvider _certificateProvider;
|
||||
private readonly ILogger<WebhookCertificateHealthCheck> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly TimeSpan _expiryThreshold = TimeSpan.FromDays(7);
|
||||
|
||||
public WebhookCertificateHealthCheck(
|
||||
IWebhookCertificateProvider certificateProvider,
|
||||
ILogger<WebhookCertificateHealthCheck> logger)
|
||||
ILogger<WebhookCertificateHealthCheck> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_certificateProvider = certificateProvider;
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||
@@ -22,7 +25,7 @@ public sealed class WebhookCertificateHealthCheck : IHealthCheck
|
||||
{
|
||||
var certificate = _certificateProvider.GetCertificate();
|
||||
var expires = certificate.NotAfter.ToUniversalTime();
|
||||
var remaining = expires - DateTimeOffset.UtcNow;
|
||||
var remaining = expires - _timeProvider.GetUtcNow();
|
||||
|
||||
if (remaining <= TimeSpan.Zero)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user