Skip to content

Commit 635d763

Browse files
committed
refactor(kubernetes): switch watchers to streaming
- Migrates watchers from Http-based list calls to streaming watch API using IAsyncEnumerable - Updates core watcher infrastructure to consume streaming results and adjust OnGetWatcher signature - Reworks item watchers (ConfigMap, Namespace, Secret) to use WatchList*Async methods - Removes dependency on k8s.Autorest and outdated Http-based watch path - Aligns tests and minor formatting to reflect streaming approach - Updates central NuGet package versions to unified 9.1.81 - Adds local Claude permissions configuration for restricted commands
1 parent ea8e891 commit 635d763

File tree

8 files changed

+45
-45
lines changed

8 files changed

+45
-45
lines changed

.claude/settings.local.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(dotnet build:*)"
5+
],
6+
"deny": [],
7+
"ask": []
8+
}
9+
}

Directory.Packages.props

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
<Project>
2-
<PropertyGroup>
3-
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4-
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
5-
</PropertyGroup>
6-
<ItemGroup>
7-
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
8-
<PackageVersion Include="ES.FX.Ignite" Version="9.1.38" />
9-
<PackageVersion Include="ES.FX.Ignite.KubernetesClient" Version="9.1.38" />
10-
<PackageVersion Include="ES.FX.Ignite.OpenTelemetry.Exporter.Seq" Version="9.1.38" />
11-
<PackageVersion Include="ES.FX.Ignite.Serilog" Version="9.1.38" />
12-
<PackageVersion Include="ES.FX.Additions.Newtonsoft.Json" Version="9.1.38" />
13-
<PackageVersion Include="ES.FX.Additions.KubernetesClient" Version="9.1.38" />
14-
<PackageVersion Include="JetBrains.Annotations" Version="2025.2.4" />
15-
<PackageVersion Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.7" />
16-
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.11" />
17-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
18-
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
19-
<PackageVersion Include="Moq" Version="4.20.72" />
20-
<PackageVersion Include="Polly.Core" Version="8.6.5" />
21-
<PackageVersion Include="Testcontainers.K3s" Version="4.9.0" />
22-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
23-
<PackageVersion Include="xunit.v3" Version="3.2.1" />
24-
</ItemGroup>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
8+
<PackageVersion Include="ES.FX.Ignite" Version="9.1.81" />
9+
<PackageVersion Include="ES.FX.Ignite.KubernetesClient" Version="9.1.81" />
10+
<PackageVersion Include="ES.FX.Ignite.OpenTelemetry.Exporter.Seq" Version="9.1.81" />
11+
<PackageVersion Include="ES.FX.Ignite.Serilog" Version="9.1.81" />
12+
<PackageVersion Include="ES.FX.Additions.Newtonsoft.Json" Version="9.1.81" />
13+
<PackageVersion Include="ES.FX.Additions.KubernetesClient" Version="9.1.81" />
14+
<PackageVersion Include="JetBrains.Annotations" Version="2025.2.4" />
15+
<PackageVersion Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.11" />
16+
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.11" />
17+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
18+
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
19+
<PackageVersion Include="Moq" Version="4.20.72" />
20+
<PackageVersion Include="Polly.Core" Version="8.6.5" />
21+
<PackageVersion Include="Testcontainers.K3s" Version="4.9.0" />
22+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
23+
<PackageVersion Include="xunit.v3" Version="3.2.1" />
24+
</ItemGroup>
2525
</Project>

src/ES.Kubernetes.Reflector/Watchers/ConfigMapWatcher.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using ES.Kubernetes.Reflector.Watchers.Core;
33
using ES.Kubernetes.Reflector.Watchers.Core.Events;
44
using k8s;
5-
using k8s.Autorest;
65
using k8s.Models;
76
using Microsoft.Extensions.Options;
87

@@ -17,8 +16,8 @@ public class ConfigMapWatcher(
1716
: WatcherBackgroundService<V1ConfigMap, V1ConfigMapList>(
1817
logger, options, watcherEventHandlers, watcherClosedHandlers)
1918
{
20-
protected override Task<HttpOperationResponse<V1ConfigMapList>> OnGetWatcher(CancellationToken cancellationToken) =>
21-
kubernetes.CoreV1.ListConfigMapForAllNamespacesWithHttpMessagesAsync(watch: true,
19+
protected override IAsyncEnumerable<(WatchEventType, V1ConfigMap)> OnGetWatcher(CancellationToken cancellationToken) =>
20+
kubernetes.CoreV1.WatchListConfigMapForAllNamespacesAsync(
2221
timeoutSeconds: WatcherTimeout,
2322
cancellationToken: cancellationToken);
2423
}

src/ES.Kubernetes.Reflector/Watchers/Core/WatcherBackgroundService.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using ES.Kubernetes.Reflector.Configuration;
44
using ES.Kubernetes.Reflector.Watchers.Core.Events;
55
using k8s;
6-
using k8s.Autorest;
76
using k8s.Models;
87
using Microsoft.Extensions.Options;
98

@@ -57,8 +56,7 @@ await watcherEventHandler.Handle(new WatcherEvent
5756
}
5857
}, cancellationToken);
5958

60-
using var watcher = OnGetWatcher(cancellationToken);
61-
var watchList = watcher.WatchAsync<TResource, TResourceList>(cancellationToken: cancellationToken);
59+
var watchList = OnGetWatcher(cancellationToken);
6260

6361
try
6462
{
@@ -106,7 +104,7 @@ await handler.Handle(new WatcherClosed
106104
}
107105
}
108106

109-
protected abstract Task<HttpOperationResponse<TResourceList>> OnGetWatcher(CancellationToken cancellationToken);
107+
protected abstract IAsyncEnumerable<(WatchEventType, TResource)> OnGetWatcher(CancellationToken cancellationToken);
110108

111109
protected virtual Task<bool> OnResourceIgnoreCheck(TResource item) => Task.FromResult(false);
112110
}

src/ES.Kubernetes.Reflector/Watchers/NamespaceWatcher.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using ES.Kubernetes.Reflector.Watchers.Core;
33
using ES.Kubernetes.Reflector.Watchers.Core.Events;
44
using k8s;
5-
using k8s.Autorest;
65
using k8s.Models;
76
using Microsoft.Extensions.Options;
87

@@ -17,7 +16,9 @@ public class NamespaceWatcher(
1716
: WatcherBackgroundService<V1Namespace, V1NamespaceList>(
1817
logger, options, watcherEventHandlers, watcherClosedHandlers)
1918
{
20-
protected override Task<HttpOperationResponse<V1NamespaceList>> OnGetWatcher(CancellationToken cancellationToken) =>
21-
kubernetes.CoreV1.ListNamespaceWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
19+
protected override IAsyncEnumerable<(WatchEventType, V1Namespace)>
20+
OnGetWatcher(CancellationToken cancellationToken) =>
21+
kubernetes.CoreV1.WatchListNamespaceAsync(
22+
timeoutSeconds: WatcherTimeout,
2223
cancellationToken: cancellationToken);
2324
}

src/ES.Kubernetes.Reflector/Watchers/SecretWatcher.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using ES.Kubernetes.Reflector.Watchers.Core;
33
using ES.Kubernetes.Reflector.Watchers.Core.Events;
44
using k8s;
5-
using k8s.Autorest;
65
using k8s.Models;
76
using Microsoft.Extensions.Options;
87

@@ -17,8 +16,8 @@ public class SecretWatcher(
1716
: WatcherBackgroundService<V1Secret, V1SecretList>(
1817
logger, options, watcherEventHandlers, watcherClosedHandlers)
1918
{
20-
protected override Task<HttpOperationResponse<V1SecretList>> OnGetWatcher(CancellationToken cancellationToken) =>
21-
kubernetes.CoreV1.ListSecretForAllNamespacesWithHttpMessagesAsync(watch: true,
19+
protected override IAsyncEnumerable<(WatchEventType, V1Secret)> OnGetWatcher(CancellationToken cancellationToken) =>
20+
kubernetes.CoreV1.WatchListSecretForAllNamespacesAsync(
2221
timeoutSeconds: WatcherTimeout,
2322
cancellationToken: cancellationToken);
2423

tests/ES.Kubernetes.Reflector.Tests/Fixtures/ReflectorFixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
3030
builder.UseEnvironment("tests");
3131
builder.ConfigureServices(services =>
3232
{
33-
var kubernetesClientConfiguration = services.SingleOrDefault(
34-
d => d.ServiceType == typeof(KubernetesClientConfiguration));
33+
var kubernetesClientConfiguration =
34+
services.SingleOrDefault(d => d.ServiceType == typeof(KubernetesClientConfiguration));
3535
if (kubernetesClientConfiguration is not null) services.Remove(kubernetesClientConfiguration);
3636

3737
services.AddSingleton(s =>

tests/ES.Kubernetes.Reflector.Tests/Integration/HealthCheckIntegrationTests.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
using System.Net;
2-
using System.Threading;
32
using ES.FX.Ignite.Configuration;
43
using ES.Kubernetes.Reflector.Tests.Integration.Base;
54
using ES.Kubernetes.Reflector.Tests.Integration.Fixtures;
65
using JetBrains.Annotations;
7-
using k8s;
86
using Microsoft.Extensions.DependencyInjection;
9-
using Microsoft.Extensions.Diagnostics.HealthChecks;
10-
using Polly.Retry;
11-
using Polly;
12-
using k8s.Autorest;
137

148
[assembly: AssemblyFixture(typeof(ReflectorIntegrationFixture))]
159

@@ -29,7 +23,7 @@ public async Task LivenessHealthCheck_Should_Return_Healthy()
2923

3024
var response = await httpClient.GetAsync(settings.AspNetCore.HealthChecks.LivenessEndpointPath,
3125
TestContext.Current.CancellationToken);
32-
Assert.Equal(HttpStatusCode.OK,response.StatusCode);
26+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
3327
}
3428

3529
[Fact]

0 commit comments

Comments
 (0)