From 0f9f127494c75a084445ed7cde1443044f4ae979 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Fri, 29 Dec 2023 18:31:13 +0100 Subject: [PATCH] Dhcp Lease Queue worker --- src/pdns-dhcp/Dhcp/DhcpLeaseQueue.cs | 18 ++++++- src/pdns-dhcp/Dns/DnsRepository.cs | 4 +- src/pdns-dhcp/Kea/IKeaDhcpLeaseHandler.cs | 4 +- src/pdns-dhcp/Kea/IKeaFactory.cs | 14 ++++++ src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs | 6 ++- src/pdns-dhcp/Kea/KeaDhcp6LeaseHandler.cs | 6 ++- src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs | 19 ++++--- src/pdns-dhcp/Kea/KeaService.cs | 50 +++++++++++++++++++ src/pdns-dhcp/Program.cs | 13 +++-- .../{DhcpLeaseWatcher.cs => DhcpWatcher.cs} | 18 ++----- src/pdns-dhcp/Services/DnsQueueWorker.cs | 31 ++++++++++++ .../Services/IDhcpLeaseWatcherFactory.cs | 13 ----- src/pdns-dhcp/Services/IDhcpWatcherFactory.cs | 11 ++++ src/pdns-dhcp/Services/PowerDnsBackend.cs | 31 ------------ 14 files changed, 164 insertions(+), 74 deletions(-) create mode 100644 src/pdns-dhcp/Kea/IKeaFactory.cs create mode 100644 src/pdns-dhcp/Kea/KeaService.cs rename src/pdns-dhcp/Services/{DhcpLeaseWatcher.cs => DhcpWatcher.cs} (73%) create mode 100644 src/pdns-dhcp/Services/DnsQueueWorker.cs delete mode 100644 src/pdns-dhcp/Services/IDhcpLeaseWatcherFactory.cs create mode 100644 src/pdns-dhcp/Services/IDhcpWatcherFactory.cs delete mode 100644 src/pdns-dhcp/Services/PowerDnsBackend.cs diff --git a/src/pdns-dhcp/Dhcp/DhcpLeaseQueue.cs b/src/pdns-dhcp/Dhcp/DhcpLeaseQueue.cs index 0d72356..f4bb4b6 100644 --- a/src/pdns-dhcp/Dhcp/DhcpLeaseQueue.cs +++ b/src/pdns-dhcp/Dhcp/DhcpLeaseQueue.cs @@ -7,7 +7,23 @@ namespace pdns_dhcp.Dhcp; public class DhcpLeaseQueue { - private readonly Channel _pipe = Channel.CreateUnbounded(); + private readonly Channel _pipe; + private readonly ChannelReader _reader; + private readonly ChannelWriter _writer; + + public ref readonly ChannelReader Reader => ref _reader; + + public DhcpLeaseQueue() + { + _pipe = Channel.CreateUnbounded(); + _reader = _pipe.Reader; + _writer = _pipe.Writer; + } + + public ValueTask Write(DhcpLeaseChange change, CancellationToken cancellationToken = default) + { + return _writer.WriteAsync(change, cancellationToken); + } } public readonly record struct DhcpLeaseChange(IPAddress Address, string FQDN, DhcpLeaseIdentifier Identifier, TimeSpan Lifetime) diff --git a/src/pdns-dhcp/Dns/DnsRepository.cs b/src/pdns-dhcp/Dns/DnsRepository.cs index c76f955..1b2f8be 100644 --- a/src/pdns-dhcp/Dns/DnsRepository.cs +++ b/src/pdns-dhcp/Dns/DnsRepository.cs @@ -40,10 +40,10 @@ public class DnsRepository cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } - public async ValueTask Record(DhcpLeaseChange leaseChange) + public async ValueTask Record(DhcpLeaseChange leaseChange, CancellationToken cancellationToken = default) { // just lock that thing. - using (await _recordLock.AcquireLockAsync(CancellationToken.None).ConfigureAwait(false)) + using (await _recordLock.AcquireLockAsync(cancellationToken).ConfigureAwait(false)) { RecordContinuation(leaseChange); } diff --git a/src/pdns-dhcp/Kea/IKeaDhcpLeaseHandler.cs b/src/pdns-dhcp/Kea/IKeaDhcpLeaseHandler.cs index 17e689f..df1fccf 100644 --- a/src/pdns-dhcp/Kea/IKeaDhcpLeaseHandler.cs +++ b/src/pdns-dhcp/Kea/IKeaDhcpLeaseHandler.cs @@ -1,8 +1,10 @@ using nietras.SeparatedValues; +using pdns_dhcp.Dhcp; + namespace pdns_dhcp.Kea; public interface IKeaDhcpLeaseHandler { - void Handle(in SepReader.Row row); + DhcpLeaseChange? Handle(in SepReader.Row row); } diff --git a/src/pdns-dhcp/Kea/IKeaFactory.cs b/src/pdns-dhcp/Kea/IKeaFactory.cs new file mode 100644 index 0000000..55f1eb5 --- /dev/null +++ b/src/pdns-dhcp/Kea/IKeaFactory.cs @@ -0,0 +1,14 @@ +using pdns_dhcp.Options; + +using Stl.Interception; + +namespace pdns_dhcp.Kea; + +public interface IKeaFactory : IRequiresFullProxy +{ + KeaDhcp4LeaseHandler CreateHandler4(); + + KeaDhcp6LeaseHandler CreateHandler6(); + + KeaDhcpLeaseWatcher CreateWatcher(IKeaDhcpLeaseHandler handler, KeaDhcpServerOptions options); +} diff --git a/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs b/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs index 5af3533..ecc716a 100644 --- a/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs +++ b/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs @@ -1,11 +1,15 @@ using nietras.SeparatedValues; +using pdns_dhcp.Dhcp; + namespace pdns_dhcp.Kea; public class KeaDhcp4LeaseHandler : IKeaDhcpLeaseHandler { - public void Handle(in SepReader.Row row) + public DhcpLeaseChange? Handle(in SepReader.Row row) { KeaDhcp4Lease lease = KeaDhcp4Lease.Parse(row); + + return default; } } diff --git a/src/pdns-dhcp/Kea/KeaDhcp6LeaseHandler.cs b/src/pdns-dhcp/Kea/KeaDhcp6LeaseHandler.cs index b79f0b0..39113a8 100644 --- a/src/pdns-dhcp/Kea/KeaDhcp6LeaseHandler.cs +++ b/src/pdns-dhcp/Kea/KeaDhcp6LeaseHandler.cs @@ -1,11 +1,15 @@ using nietras.SeparatedValues; +using pdns_dhcp.Dhcp; + namespace pdns_dhcp.Kea; public class KeaDhcp6LeaseHandler : IKeaDhcpLeaseHandler { - public void Handle(in SepReader.Row row) + public DhcpLeaseChange? Handle(in SepReader.Row row) { KeaDhcp6Lease lease = KeaDhcp6Lease.Parse(row); + + return default; } } diff --git a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs index 3e7b428..460a72c 100644 --- a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs +++ b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs @@ -7,36 +7,38 @@ using Microsoft.Extensions.Hosting; using nietras.SeparatedValues; +using pdns_dhcp.Dhcp; using pdns_dhcp.Options; namespace pdns_dhcp.Kea; -public sealed class KeaDhcpLeaseWatcher : IHostedService - where T : IKeaDhcpLeaseHandler +public sealed class KeaDhcpLeaseWatcher : IHostedService { private static readonly FileStreamOptions LeaseFileStreamOptions = new() { Access = FileAccess.Read, Mode = FileMode.Open, - Options = FileOptions.SequentialScan, + Options = FileOptions.SequentialScan | FileOptions.Asynchronous, Share = (FileShare)7, }; private readonly Decoder _decoder; private readonly FileSystemWatcher _fsw; - private readonly T _handler; + private readonly IKeaDhcpLeaseHandler _handler; private readonly string _leaseFile; private readonly Pipe _pipe; + private readonly DhcpLeaseQueue _queue; private Channel? _eventChannel; private Task? _executeTask; private CancellationTokenSource? _stoppingCts; private KeaDhcpServerOptions Options { get; } - public KeaDhcpLeaseWatcher(KeaDhcpServerOptions options, T handler) + public KeaDhcpLeaseWatcher(KeaDhcpServerOptions options, IKeaDhcpLeaseHandler handler, DhcpLeaseQueue queue) { Options = options = options with { Leases = PathEx.ExpandPath(options.Leases) }; _handler = handler; + _queue = queue; var leases = options.Leases.AsSpan(); if (leases.IsWhiteSpace()) @@ -177,7 +179,12 @@ public sealed class KeaDhcpLeaseWatcher : IHostedService return; } - _handler.Handle(reader.Current); + if (_handler.Handle(reader.Current) is not { } lease) + { + continue; + } + + await _queue.Write(lease, stoppingToken).ConfigureAwait(false); } var memory = writer.GetMemory(); diff --git a/src/pdns-dhcp/Kea/KeaService.cs b/src/pdns-dhcp/Kea/KeaService.cs new file mode 100644 index 0000000..5087408 --- /dev/null +++ b/src/pdns-dhcp/Kea/KeaService.cs @@ -0,0 +1,50 @@ +using System.Collections.Immutable; + +using Microsoft.Extensions.Hosting; + +using pdns_dhcp.Options; + +namespace pdns_dhcp.Kea; + +public class KeaService : IHostedService +{ + private readonly ImmutableArray _services; + + public KeaService(KeaDhcpOptions options, IKeaFactory factory) + { + if (options.Dhcp4 is { } dhcp4Options) + { + _services.Add(factory.CreateWatcher(factory.CreateHandler4(), dhcp4Options)); + } + + if (options.Dhcp6 is { } dhcp6Options) + { + _services.Add(factory.CreateWatcher(factory.CreateHandler6(), dhcp6Options)); + } + } + + public Task StartAsync(CancellationToken cancellationToken = default) + { + Task[] tasks = new Task[_services.Length]; + for (int i = 0; i < tasks.Length; i++) + { + tasks[i] = _services[i].StartAsync(cancellationToken); + } + + return Task.WhenAll(tasks); + } + + public async Task StopAsync(CancellationToken cancellationToken = default) + { + Task[] tasks = new Task[_services.Length]; + for (int i = 0; i < tasks.Length; i++) + { + tasks[i] = _services[i].StopAsync(cancellationToken); + } + + var waitTask = Task.WhenAll(tasks); + TaskCompletionSource taskCompletionSource = new(); + using var registration = cancellationToken.Register(s => ((TaskCompletionSource)s!).SetCanceled(), taskCompletionSource); + await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(continueOnCapturedContext: false); + } +} diff --git a/src/pdns-dhcp/Program.cs b/src/pdns-dhcp/Program.cs index ca64e74..405219b 100644 --- a/src/pdns-dhcp/Program.cs +++ b/src/pdns-dhcp/Program.cs @@ -9,6 +9,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using pdns_dhcp.Connections; +using pdns_dhcp.Dhcp; +using pdns_dhcp.Dns; using pdns_dhcp.Kea; using pdns_dhcp.Options; using pdns_dhcp.PowerDns; @@ -21,13 +23,14 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.Configure(builder.Configuration.GetRequiredSection("Dhcp")); builder.Services.Configure(builder.Configuration.GetRequiredSection("PowerDns")); -builder.Services.AddHostedService(); -builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); -builder.Services.AddTypedFactory(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); -builder.Services.AddTransient(); -builder.Services.AddTransient(); +builder.Services.AddTypedFactory(); +builder.Services.AddTypedFactory(); builder.Services.Configure(options => { diff --git a/src/pdns-dhcp/Services/DhcpLeaseWatcher.cs b/src/pdns-dhcp/Services/DhcpWatcher.cs similarity index 73% rename from src/pdns-dhcp/Services/DhcpLeaseWatcher.cs rename to src/pdns-dhcp/Services/DhcpWatcher.cs index b5b7172..0ce62ed 100644 --- a/src/pdns-dhcp/Services/DhcpLeaseWatcher.cs +++ b/src/pdns-dhcp/Services/DhcpWatcher.cs @@ -7,31 +7,23 @@ using pdns_dhcp.Options; namespace pdns_dhcp.Services; -public class DhcpLeaseWatcher : IHostedService +public class DhcpWatcher : IHostedService { private readonly ImmutableArray _services; - public DhcpLeaseWatcher(IOptions options, IDhcpLeaseWatcherFactory factory) + public DhcpWatcher(IOptions options, IDhcpWatcherFactory factory) { var dhcpOptions = options.Value; var services = ImmutableArray.CreateBuilder(); if (dhcpOptions.Kea is { } keaOptions) { - if (keaOptions.Dhcp4 is { } dhcp4Options) - { - services.Add(factory.KeaDhcp4Watcher(dhcp4Options)); - } - - if (keaOptions.Dhcp6 is { } dhcp6Options) - { - services.Add(factory.KeaDhcp6Watcher(dhcp6Options)); - } + services.Add(factory.KeaService(keaOptions)); } _services = services.DrainToImmutable(); } - public Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken = default) { Task[] tasks = new Task[_services.Length]; for (int i = 0; i < tasks.Length; i++) @@ -42,7 +34,7 @@ public class DhcpLeaseWatcher : IHostedService return Task.WhenAll(tasks); } - public async Task StopAsync(CancellationToken cancellationToken) + public async Task StopAsync(CancellationToken cancellationToken = default) { Task[] tasks = new Task[_services.Length]; for (int i = 0; i < tasks.Length; i++) diff --git a/src/pdns-dhcp/Services/DnsQueueWorker.cs b/src/pdns-dhcp/Services/DnsQueueWorker.cs new file mode 100644 index 0000000..ca94e34 --- /dev/null +++ b/src/pdns-dhcp/Services/DnsQueueWorker.cs @@ -0,0 +1,31 @@ +using System.Threading.Channels; + +using Microsoft.Extensions.Hosting; + +using pdns_dhcp.Dhcp; +using pdns_dhcp.Dns; + +namespace pdns_dhcp.Services; + +public class DnsQueueWorker : BackgroundService +{ + private readonly ChannelReader _channelReader; + private readonly DnsRepository _repository; + + public DnsQueueWorker(DhcpLeaseQueue queue, DnsRepository repository) + { + _channelReader = queue.Reader; + _repository = repository; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (await _channelReader.WaitToReadAsync(stoppingToken).ConfigureAwait(false)) + { + while (_channelReader.TryRead(out var lease)) + { + await _repository.Record(default, stoppingToken).ConfigureAwait(false); + } + } + } +} diff --git a/src/pdns-dhcp/Services/IDhcpLeaseWatcherFactory.cs b/src/pdns-dhcp/Services/IDhcpLeaseWatcherFactory.cs deleted file mode 100644 index 4d023aa..0000000 --- a/src/pdns-dhcp/Services/IDhcpLeaseWatcherFactory.cs +++ /dev/null @@ -1,13 +0,0 @@ -using pdns_dhcp.Kea; -using pdns_dhcp.Options; - -using Stl.Interception; - -namespace pdns_dhcp.Services; - -public interface IDhcpLeaseWatcherFactory : IRequiresFullProxy -{ - KeaDhcpLeaseWatcher KeaDhcp4Watcher(KeaDhcpServerOptions options); - - KeaDhcpLeaseWatcher KeaDhcp6Watcher(KeaDhcpServerOptions options); -} diff --git a/src/pdns-dhcp/Services/IDhcpWatcherFactory.cs b/src/pdns-dhcp/Services/IDhcpWatcherFactory.cs new file mode 100644 index 0000000..cdb644c --- /dev/null +++ b/src/pdns-dhcp/Services/IDhcpWatcherFactory.cs @@ -0,0 +1,11 @@ +using pdns_dhcp.Kea; +using pdns_dhcp.Options; + +using Stl.Interception; + +namespace pdns_dhcp.Services; + +public interface IDhcpWatcherFactory : IRequiresFullProxy +{ + KeaService KeaService(KeaDhcpOptions options); +} diff --git a/src/pdns-dhcp/Services/PowerDnsBackend.cs b/src/pdns-dhcp/Services/PowerDnsBackend.cs deleted file mode 100644 index 5fd3f8d..0000000 --- a/src/pdns-dhcp/Services/PowerDnsBackend.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.Extensions.Hosting; - -namespace pdns_dhcp.Services; - -public class PowerDnsBackend : BackgroundService -{ - public PowerDnsBackend() - { - } - - ~PowerDnsBackend() - { - DisposeCore(); - } - - protected override Task ExecuteAsync(CancellationToken stoppingToken) - { - return Task.CompletedTask; - } - - public override void Dispose() - { - base.Dispose(); - DisposeCore(); - GC.SuppressFinalize(this); - } - - private void DisposeCore() - { - } -}