diff --git a/YARP.slnx b/YARP.slnx index 8038a97274..c2535b84c6 100644 --- a/YARP.slnx +++ b/YARP.slnx @@ -54,6 +54,7 @@ + diff --git a/src/Kubernetes.Controller/Management/KubernetesReverseProxyServiceCollectionExtensions.cs b/src/Kubernetes.Controller/Management/KubernetesReverseProxyServiceCollectionExtensions.cs index 663fa59217..521d6db166 100644 --- a/src/Kubernetes.Controller/Management/KubernetesReverseProxyServiceCollectionExtensions.cs +++ b/src/Kubernetes.Controller/Management/KubernetesReverseProxyServiceCollectionExtensions.cs @@ -80,7 +80,7 @@ public static IServiceCollection AddKubernetesControllerRuntime(this IServiceCol services.AddHostedService(); services.AddSingleton(); services.AddTransient(); - services.Configure(config.GetSection("Yarp")); + services.Configure(o => config.GetSection("Yarp").Bind(o)); // Register the necessary Kubernetes resource informers services.RegisterResourceInformer(); diff --git a/src/Kubernetes.Controller/Protocol/DispatchActionResult.cs b/src/Kubernetes.Controller/Protocol/DispatchActionResult.cs index 771b182a1d..ff5d339e76 100644 --- a/src/Kubernetes.Controller/Protocol/DispatchActionResult.cs +++ b/src/Kubernetes.Controller/Protocol/DispatchActionResult.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Yarp.Kubernetes.Controller.Protocol; using Yarp.Kubernetes.Protocol; namespace Yarp.Kubernetes.Controller.Dispatching; @@ -54,7 +55,7 @@ public async Task ExecuteResultAsync(ActionContext context) var utf8Bytes = JsonSerializer.SerializeToUtf8Bytes(new Message { MessageType = MessageType.Heartbeat - }); + }, KubernetesJsonSerializerContext.Default.Message); while (!cancellationToken.IsCancellationRequested) { diff --git a/src/Kubernetes.Controller/Protocol/DispatchConfigProvider.cs b/src/Kubernetes.Controller/Protocol/DispatchConfigProvider.cs index 000c8e4036..566122f51f 100644 --- a/src/Kubernetes.Controller/Protocol/DispatchConfigProvider.cs +++ b/src/Kubernetes.Controller/Protocol/DispatchConfigProvider.cs @@ -34,7 +34,7 @@ public async Task UpdateAsync(IReadOnlyList routes, IReadOnlyList))] +[JsonSerializable(typeof(List))] +internal sealed partial class KubernetesJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/Kubernetes.Controller/Protocol/Message.cs b/src/Kubernetes.Controller/Protocol/Message.cs index 4bdaddd916..8b6245afd9 100644 --- a/src/Kubernetes.Controller/Protocol/Message.cs +++ b/src/Kubernetes.Controller/Protocol/Message.cs @@ -16,7 +16,7 @@ public enum MessageType public struct Message { - [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonConverter(typeof(JsonStringEnumConverter))] public MessageType MessageType { get; set; } public string Key { get; set; } diff --git a/src/Kubernetes.Controller/Protocol/Receiver.cs b/src/Kubernetes.Controller/Protocol/Receiver.cs index 46830002a9..b5f48858b8 100644 --- a/src/Kubernetes.Controller/Protocol/Receiver.cs +++ b/src/Kubernetes.Controller/Protocol/Receiver.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Options; using Yarp.Kubernetes.Controller.Configuration; using Yarp.Kubernetes.Controller.Hosting; +using Yarp.Kubernetes.Controller.Protocol; using Yarp.Kubernetes.Controller.Rate; namespace Yarp.Kubernetes.Protocol; @@ -65,7 +66,7 @@ public override async Task RunAsync(CancellationToken cancellationToken) break; } - var message = System.Text.Json.JsonSerializer.Deserialize(json); + var message = System.Text.Json.JsonSerializer.Deserialize(json, KubernetesJsonSerializerContext.Default.Message); Logger.LogInformation("Received {MessageType} for {MessageKey}", message.MessageType, message.Key); Logger.LogInformation(json); diff --git a/src/Kubernetes.Controller/Services/Reconciler.cs b/src/Kubernetes.Controller/Services/Reconciler.cs index a5302537f4..c2733062cb 100644 --- a/src/Kubernetes.Controller/Services/Reconciler.cs +++ b/src/Kubernetes.Controller/Services/Reconciler.cs @@ -11,6 +11,7 @@ using Yarp.Kubernetes.Controller.Client; using Yarp.Kubernetes.Controller.Configuration; using Yarp.Kubernetes.Controller.Converters; +using Yarp.Kubernetes.Controller.Protocol; namespace Yarp.Kubernetes.Controller.Services; @@ -63,8 +64,8 @@ public async Task ProcessAsync(CancellationToken cancellationToken) var clusters = configContext.BuildClusterConfig(); - _logger.LogInformation(JsonSerializer.Serialize(configContext.Routes)); - _logger.LogInformation(JsonSerializer.Serialize(clusters)); + _logger.LogInformation(JsonSerializer.Serialize(configContext.Routes, KubernetesJsonSerializerContext.Default.ListRouteConfig)); + _logger.LogInformation(JsonSerializer.Serialize(clusters, KubernetesJsonSerializerContext.Default.ListClusterConfig)); await _updateConfig.UpdateAsync(configContext.Routes, clusters, cancellationToken).ConfigureAwait(false); await _ingressResourceStatusUpdater.UpdateStatusAsync(cancellationToken); diff --git a/src/Kubernetes.Controller/Yarp.Kubernetes.Controller.csproj b/src/Kubernetes.Controller/Yarp.Kubernetes.Controller.csproj index baae88ecf9..c39c7ca179 100644 --- a/src/Kubernetes.Controller/Yarp.Kubernetes.Controller.csproj +++ b/src/Kubernetes.Controller/Yarp.Kubernetes.Controller.csproj @@ -7,6 +7,7 @@ $(NoWarn);CS8002 true false + true yarp;dotnet;reverse-proxy;aspnetcore;kubernetes diff --git a/testassets/Kubernetes.AotCompatibility.TestApp/Program.cs b/testassets/Kubernetes.AotCompatibility.TestApp/Program.cs new file mode 100644 index 0000000000..1bce089e26 --- /dev/null +++ b/testassets/Kubernetes.AotCompatibility.TestApp/Program.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// This app is used to test AOT compatibility of all AOT-compatible YARP assemblies. +// It exercises the main public API surface to ensure no AOT/trimming warnings +// are emitted at build or publish time. + +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Yarp.Kubernetes.Protocol; + +// Combined controller scenario (ingress controller + YARP reverse proxy) +{ + var builder = WebApplication.CreateBuilder(args); + builder.WebHost.UseKubernetesReverseProxyCertificateSelector(); + builder.Services.AddKubernetesReverseProxy(builder.Configuration); + _ = builder.Build(); +} + +// Monitor-only scenario (ingress monitor + dispatch controller) +{ + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddKubernetesIngressMonitor(builder.Configuration); + builder.Services.AddControllers().AddKubernetesDispatchController(); + _ = builder.Build(); +} + +// Receiver scenario (side-car that receives config from ingress monitor) +{ + var builder = WebApplication.CreateBuilder(args); + builder.Services.Configure(builder.Configuration.Bind); + builder.Services.AddHostedService(); + builder.Services.AddReverseProxy().LoadFromMessages(); + _ = builder.Build(); +} + +// ReverseProxy standalone scenario +{ + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddReverseProxy() + .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy")); + _ = builder.Build(); +} + +// TelemetryConsumption scenario +{ + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddTelemetryListeners(); + _ = builder.Build(); +} diff --git a/testassets/Kubernetes.AotCompatibility.TestApp/Yarp.Kubernetes.AotCompatibility.TestApp.csproj b/testassets/Kubernetes.AotCompatibility.TestApp/Yarp.Kubernetes.AotCompatibility.TestApp.csproj new file mode 100644 index 0000000000..c93ea72d29 --- /dev/null +++ b/testassets/Kubernetes.AotCompatibility.TestApp/Yarp.Kubernetes.AotCompatibility.TestApp.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + Exe + true + enable + + + + + + + + + + + + + + +