Skip to content

Commit ff58548

Browse files
committed
feat(configuration): add centralized project configuration files
- Introduced `Directory.Build.props` and `Directory.Packages.props` for centralized property and package version management. - Updated solution file to include new configuration files as solution items. - Enhanced logging configuration in `appsettings.json` for better observability with Serilog and OpenTelemetry settings. - Refactored resource mirror classes to utilize dependency injection for Kubernetes client, improving testability and maintainability. - Adjusted Dockerfile to expose port 8080 instead of 25080. BREAKING CHANGE: The application now requires updated configurations for logging and Kubernetes client setup.
1 parent 361b8c9 commit ff58548

18 files changed

+261
-197
lines changed

src/Directory.Build.props

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project>
2+
<!-- Project defaults -->
3+
<PropertyGroup>
4+
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
5+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<!--Generate debug symbols and embed them in the build output.-->
9+
<DebugType>embedded</DebugType>
10+
<DebugSymbols>true</DebugSymbols>
11+
<!--Set the solution directory to the parent directory of the build file.-->
12+
<SolutionDir Condition="'$(SolutionDir)' == ''">$(MSBuildThisFileDirectory)..\</SolutionDir>
13+
<!--Generate XML documentation file-->
14+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
15+
<!--Disable warnings from XML documentation - CS1591;CS1571;CS1573;CS1574;CS1723; - -->
16+
<!--Disable warnings NuGet vulnerabilities - NU1901;NU1902;NU1903; - -->
17+
<NoWarn>CS1591;CS1571;CS1573;CS1574;CS1723;NU1901;NU1902;NU1903;</NoWarn>
18+
</PropertyGroup>
19+
20+
<!-- JetBrains.Annotations -->
21+
<ItemGroup>
22+
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
23+
</ItemGroup>
24+
25+
<!--Test projects-->
26+
<ItemGroup Condition="'$(MSBuildProjectName)' == '' Or $(MSBuildProjectName.Contains('.Tests'))">
27+
<AssemblyAttribute Include="System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute" />
28+
</ItemGroup>
29+
<PropertyGroup Condition="'$(MSBuildProjectName)' == '' Or $(MSBuildProjectName.Contains('.Tests'))">
30+
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
31+
<VSTestLogger>trx%3bLogFileName=$(MSBuildProjectName).trx</VSTestLogger>
32+
<VSTestResultsDirectory>$(MSBuildThisFileDirectory).artifacts/TestResults</VSTestResultsDirectory>
33+
</PropertyGroup>
34+
</Project>

src/Directory.Packages.props

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageVersion Include="ES.FX" Version="9.1.0-develop.146" />
8+
<PackageVersion Include="ES.FX.Ignite" Version="9.1.0-develop.146" />
9+
<PackageVersion Include="ES.FX.Ignite.OpenTelemetry.Exporter.Seq" Version="9.1.0-develop.146" />
10+
<PackageVersion Include="ES.FX.Ignite.Serilog" Version="9.1.0-develop.146" />
11+
<PackageVersion Include="JetBrains.Annotations" Version="2024.3.0" />
12+
<PackageVersion Include="KubernetesClient" Version="16.0.2" />
13+
<PackageVersion Include="MediatR" Version="12.4.1" />
14+
<PackageVersion Include="Microsoft.AspNetCore.JsonPatch" Version="9.0.2" />
15+
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
16+
</ItemGroup>
17+
</Project>

src/ES.Kubernetes.Reflector.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ VisualStudioVersion = 17.0.31710.8
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ES.Kubernetes.Reflector", "ES.Kubernetes.Reflector\ES.Kubernetes.Reflector.csproj", "{96CDE0CF-7782-490B-8AF6-4219DB0236B3}"
77
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "....Solution Items", "....Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
9+
ProjectSection(SolutionItems) = preProject
10+
Directory.Build.props = Directory.Build.props
11+
EndProjectSection
12+
EndProject
813
Global
914
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1015
Debug|Any CPU = Debug|Any CPU

src/ES.Kubernetes.Reflector/Core/ConfigMapMirror.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66

77
namespace ES.Kubernetes.Reflector.Core;
88

9-
public class ConfigMapMirror : ResourceMirror<V1ConfigMap>
9+
public class ConfigMapMirror(ILogger<ConfigMapMirror> logger, IServiceProvider serviceProvider)
10+
: ResourceMirror<V1ConfigMap>(logger, serviceProvider)
1011
{
11-
public ConfigMapMirror(ILogger<ConfigMapMirror> logger, IKubernetes client) : base(logger, client)
12-
{
13-
}
12+
private readonly IServiceProvider _serviceProvider = serviceProvider;
1413

1514
protected override async Task<V1ConfigMap[]> OnResourceWithNameList(string itemRefName)
1615
{
17-
return (await Client.CoreV1.ListConfigMapForAllNamespacesAsync(fieldSelector: $"metadata.name={itemRefName}")).Items
16+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
17+
return (await client.CoreV1.ListConfigMapForAllNamespacesAsync(fieldSelector: $"metadata.name={itemRefName}")).Items
1818
.ToArray();
1919
}
2020

21-
protected override Task OnResourceApplyPatch(V1Patch patch, KubeRef refId)
21+
protected override async Task OnResourceApplyPatch(V1Patch patch, KubeRef refId)
2222
{
23-
return Client.CoreV1.PatchNamespacedConfigMapAsync(patch, refId.Name, refId.Namespace);
23+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
24+
await client.CoreV1.PatchNamespacedConfigMapAsync(patch, refId.Name, refId.Namespace);
2425
}
2526

2627
protected override Task OnResourceConfigurePatch(V1ConfigMap source, JsonPatchDocument<V1ConfigMap> patchDoc)
@@ -30,9 +31,10 @@ protected override Task OnResourceConfigurePatch(V1ConfigMap source, JsonPatchDo
3031
return Task.CompletedTask;
3132
}
3233

33-
protected override Task OnResourceCreate(V1ConfigMap item, string ns)
34+
protected override async Task OnResourceCreate(V1ConfigMap item, string ns)
3435
{
35-
return Client.CoreV1.CreateNamespacedConfigMapAsync(item, ns);
36+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
37+
await client.CoreV1.CreateNamespacedConfigMapAsync(item, ns);
3638
}
3739

3840
protected override Task<V1ConfigMap> OnResourceClone(V1ConfigMap sourceResource)
@@ -46,13 +48,15 @@ protected override Task<V1ConfigMap> OnResourceClone(V1ConfigMap sourceResource)
4648
});
4749
}
4850

49-
protected override Task OnResourceDelete(KubeRef resourceId)
51+
protected override async Task OnResourceDelete(KubeRef resourceId)
5052
{
51-
return Client.CoreV1.DeleteNamespacedConfigMapAsync(resourceId.Name, resourceId.Namespace);
53+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
54+
await client.CoreV1.DeleteNamespacedConfigMapAsync(resourceId.Name, resourceId.Namespace);
5255
}
5356

54-
protected override Task<V1ConfigMap> OnResourceGet(KubeRef refId)
57+
protected override async Task<V1ConfigMap> OnResourceGet(KubeRef refId)
5558
{
56-
return Client.CoreV1.ReadNamespacedConfigMapAsync(refId.Name, refId.Namespace);
59+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
60+
return await client.CoreV1.ReadNamespacedConfigMapAsync(refId.Name, refId.Namespace);
5761
}
5862
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,16 @@
88

99
namespace ES.Kubernetes.Reflector.Core;
1010

11-
public class ConfigMapWatcher : WatcherBackgroundService<V1ConfigMap, V1ConfigMapList>
11+
public class ConfigMapWatcher(
12+
ILogger<ConfigMapWatcher> logger,
13+
IMediator mediator,
14+
IServiceProvider serviceProvider,
15+
IOptionsMonitor<ReflectorOptions> options)
16+
: WatcherBackgroundService<V1ConfigMap, V1ConfigMapList>(logger, mediator, serviceProvider, options)
1217
{
13-
public ConfigMapWatcher(ILogger<ConfigMapWatcher> logger, IMediator mediator, IKubernetes client,
14-
IOptionsMonitor<ReflectorOptions> options) :
15-
base(logger, mediator, client, options)
18+
protected override Task<HttpOperationResponse<V1ConfigMapList>> OnGetWatcher(IKubernetes client ,CancellationToken cancellationToken)
1619
{
17-
}
18-
19-
20-
protected override Task<HttpOperationResponse<V1ConfigMapList>> OnGetWatcher(CancellationToken cancellationToken)
21-
{
22-
return Client.CoreV1.ListConfigMapForAllNamespacesWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
20+
return client.CoreV1.ListConfigMapForAllNamespacesWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
2321
cancellationToken: cancellationToken);
2422
}
2523
}

src/ES.Kubernetes.Reflector/Core/Mirroring/ResourceMirror.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
namespace ES.Kubernetes.Reflector.Core.Mirroring;
1818

19-
public abstract class ResourceMirror<TResource> :
19+
public abstract class ResourceMirror<TResource>(ILogger logger, IServiceProvider serviceProvider) :
2020
INotificationHandler<WatcherEvent>,
2121
INotificationHandler<WatcherClosed>
2222
where TResource : class, IKubernetesObject<V1ObjectMeta>
@@ -27,15 +27,7 @@ public abstract class ResourceMirror<TResource> :
2727

2828
private readonly ConcurrentDictionary<KubeRef, bool> _notFoundCache = new();
2929
private readonly ConcurrentDictionary<KubeRef, ReflectorProperties> _propertiesCache = new();
30-
protected readonly IKubernetes Client;
31-
protected readonly ILogger Logger;
32-
33-
34-
protected ResourceMirror(ILogger logger, IKubernetes client)
35-
{
36-
Logger = logger;
37-
Client = client;
38-
}
30+
protected readonly ILogger Logger = logger;
3931

4032

4133
/// <summary>
@@ -83,7 +75,7 @@ public async Task Handle(WatcherEvent notification, CancellationToken cancellati
8375
case WatchEventType.Added:
8476
case WatchEventType.Modified:
8577
{
86-
await HandleUpsert(resource, notification.Type, cancellationToken);
78+
await HandleUpsert(resource, cancellationToken);
8779
}
8880
break;
8981
case WatchEventType.Deleted:
@@ -150,7 +142,7 @@ public async Task Handle(WatcherEvent notification, CancellationToken cancellati
150142
}
151143

152144

153-
private async Task HandleUpsert(TResource resource, WatchEventType eventType, CancellationToken cancellationToken)
145+
private async Task HandleUpsert(TResource resource, CancellationToken cancellationToken)
154146
{
155147
var resourceRef = resource.GetRef();
156148
var properties = resource.GetReflectionProperties();
@@ -207,7 +199,7 @@ private async Task HandleUpsert(TResource resource, WatchEventType eventType, Ca
207199
if (_directReflectionCache.TryGetValue(resourceRef, out reflectionList))
208200
foreach (var reflectionRef in reflectionList.ToArray())
209201
{
210-
//Try to get the properties for the reflection. Otherwise remove it
202+
//Try to get the properties for the reflection. Otherwise, remove it
211203
if (!_propertiesCache.TryGetValue(reflectionRef, out var reflectionProperties))
212204
{
213205
reflectionList.Remove(reflectionRef);
@@ -334,7 +326,8 @@ private async Task AutoReflectionForSource(KubeRef resourceRef, TResource? resou
334326
var autoReflectionList = _autoReflectionCache.GetOrAdd(resourceRef, _ => new List<KubeRef>());
335327

336328
var matches = await OnResourceWithNameList(resourceRef.Name);
337-
var namespaces = (await Client.CoreV1.ListNamespaceAsync(cancellationToken: cancellationToken)).Items;
329+
using var client = serviceProvider.GetRequiredService<IKubernetes>();
330+
var namespaces = (await client.CoreV1.ListNamespaceAsync(cancellationToken: cancellationToken)).Items;
338331

339332
foreach (var match in matches)
340333
{
@@ -521,4 +514,5 @@ protected virtual Task<bool> OnResourceIgnoreCheck(TResource item)
521514
{
522515
return Task.FromResult(false);
523516
}
517+
524518
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,16 @@
88

99
namespace ES.Kubernetes.Reflector.Core;
1010

11-
public class NamespaceWatcher : WatcherBackgroundService<V1Namespace, V1NamespaceList>
11+
public class NamespaceWatcher(
12+
ILogger<NamespaceWatcher> logger,
13+
IMediator mediator,
14+
IServiceProvider serviceProvider,
15+
IOptionsMonitor<ReflectorOptions> options)
16+
: WatcherBackgroundService<V1Namespace, V1NamespaceList>(logger, mediator, serviceProvider, options)
1217
{
13-
public NamespaceWatcher(ILogger<NamespaceWatcher> logger, IMediator mediator, IKubernetes client,
14-
IOptionsMonitor<ReflectorOptions> options) :
15-
base(logger, mediator, client, options)
18+
protected override Task<HttpOperationResponse<V1NamespaceList>> OnGetWatcher(IKubernetes client,CancellationToken cancellationToken)
1619
{
17-
}
18-
19-
20-
protected override Task<HttpOperationResponse<V1NamespaceList>> OnGetWatcher(CancellationToken cancellationToken)
21-
{
22-
return Client.CoreV1.ListNamespaceWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
20+
return client.CoreV1.ListNamespaceWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
2321
cancellationToken: cancellationToken);
2422
}
2523
}

src/ES.Kubernetes.Reflector/Core/SecretMirror.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,22 @@
66

77
namespace ES.Kubernetes.Reflector.Core;
88

9-
public class SecretMirror : ResourceMirror<V1Secret>
9+
public class SecretMirror(ILogger<SecretMirror> logger, IServiceProvider serviceProvider) : ResourceMirror<V1Secret>(logger, serviceProvider)
1010
{
11-
public SecretMirror(ILogger<SecretMirror> logger, IKubernetes client) : base(logger, client)
12-
{
13-
}
11+
private readonly IServiceProvider _serviceProvider = serviceProvider;
1412

1513
protected override async Task<V1Secret[]> OnResourceWithNameList(string itemRefName)
1614
{
17-
return (await Client.CoreV1.ListSecretForAllNamespacesAsync(fieldSelector: $"metadata.name={itemRefName}")).Items
15+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
16+
return (await client.CoreV1.ListSecretForAllNamespacesAsync(fieldSelector: $"metadata.name={itemRefName}"))
17+
.Items
1818
.ToArray();
1919
}
2020

21-
protected override Task OnResourceApplyPatch(V1Patch patch, KubeRef refId)
21+
protected override async Task OnResourceApplyPatch(V1Patch patch, KubeRef refId)
2222
{
23-
return Client.CoreV1.PatchNamespacedSecretWithHttpMessagesAsync(patch, refId.Name, refId.Namespace);
23+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
24+
await client.CoreV1.PatchNamespacedSecretWithHttpMessagesAsync(patch, refId.Name, refId.Namespace);
2425
}
2526

2627
protected override Task OnResourceConfigurePatch(V1Secret source, JsonPatchDocument<V1Secret> patchDoc)
@@ -29,9 +30,10 @@ protected override Task OnResourceConfigurePatch(V1Secret source, JsonPatchDocum
2930
return Task.CompletedTask;
3031
}
3132

32-
protected override Task OnResourceCreate(V1Secret item, string ns)
33+
protected override async Task OnResourceCreate(V1Secret item, string ns)
3334
{
34-
return Client.CoreV1.CreateNamespacedSecretAsync(item, ns);
35+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
36+
await client.CoreV1.CreateNamespacedSecretAsync(item, ns);
3537
}
3638

3739
protected override Task<V1Secret> OnResourceClone(V1Secret sourceResource)
@@ -45,14 +47,16 @@ protected override Task<V1Secret> OnResourceClone(V1Secret sourceResource)
4547
});
4648
}
4749

48-
protected override Task OnResourceDelete(KubeRef resourceId)
50+
protected override async Task OnResourceDelete(KubeRef resourceId)
4951
{
50-
return Client.CoreV1.DeleteNamespacedSecretAsync(resourceId.Name, resourceId.Namespace);
52+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
53+
await client.CoreV1.DeleteNamespacedSecretAsync(resourceId.Name, resourceId.Namespace);
5154
}
5255

53-
protected override Task<V1Secret> OnResourceGet(KubeRef refId)
56+
protected override async Task<V1Secret> OnResourceGet(KubeRef refId)
5457
{
55-
return Client.CoreV1.ReadNamespacedSecretAsync(refId.Name, refId.Namespace);
58+
using var client = _serviceProvider.GetRequiredService<IKubernetes>();
59+
return await client.CoreV1.ReadNamespacedSecretAsync(refId.Name, refId.Namespace);
5660
}
5761

5862
protected override Task<bool> OnResourceIgnoreCheck(V1Secret item)

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,16 @@
88

99
namespace ES.Kubernetes.Reflector.Core;
1010

11-
public class SecretWatcher : WatcherBackgroundService<V1Secret, V1SecretList>
11+
public class SecretWatcher(
12+
ILogger<SecretWatcher> logger,
13+
IMediator mediator,
14+
IServiceProvider serviceProvider,
15+
IOptionsMonitor<ReflectorOptions> options)
16+
: WatcherBackgroundService<V1Secret, V1SecretList>(logger, mediator, serviceProvider, options)
1217
{
13-
public SecretWatcher(ILogger<SecretWatcher> logger, IMediator mediator, IKubernetes client,
14-
IOptionsMonitor<ReflectorOptions> options) :
15-
base(logger, mediator, client, options)
18+
protected override Task<HttpOperationResponse<V1SecretList>> OnGetWatcher(IKubernetes client, CancellationToken cancellationToken)
1619
{
17-
}
18-
19-
20-
protected override Task<HttpOperationResponse<V1SecretList>> OnGetWatcher(CancellationToken cancellationToken)
21-
{
22-
return Client.CoreV1.ListSecretForAllNamespacesWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
20+
return client.CoreV1.ListSecretForAllNamespacesWithHttpMessagesAsync(watch: true, timeoutSeconds: WatcherTimeout,
2321
cancellationToken: cancellationToken);
2422
}
2523
}

0 commit comments

Comments
 (0)