Skip to content

Commit 6096eba

Browse files
committed
Support for informers
1 parent b0e7d99 commit 6096eba

File tree

66 files changed

+5209
-42
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+5209
-42
lines changed

.dockerignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
**/bin/
2+
**/obj/
3+
**/out/
4+
**/layer/
5+
**Dockerfile*
6+
*/*.md

.github/workflows/nuget.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,9 @@ jobs:
3535
run: dotnet test
3636
- name: Pack
3737
run: dotnet pack --configuration Release src/KubernetesClient -o pkg
38+
- name: Pack
39+
run: dotnet pack --configuration Release src/KubernetesClient.Informers -o pkg
40+
- name: Pack
41+
run: dotnet pack --configuration Release src/KubernetesClient.DependencyInjection -o pkg
3842
- name: Push
3943
run: dotnet nuget push pkg\*.nupkg -s https://www.nuget.org/ -k ${{ secrets.nuget_api_key }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
obj/
44
bin/
55
**/TestResults
6+
pkg/**
67

78
# User-specific VS files
89
*.suo
@@ -13,3 +14,4 @@ bin/
1314
# JetBrains Rider
1415
.idea/
1516
*.sln.iml
17+
examples/informers/Dockerfile
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Hosting;
7+
8+
namespace informers
9+
{
10+
/// <summary>
11+
/// Starts all controllers registered in dependency injection container
12+
/// </summary>
13+
public class ControllerService : BackgroundService
14+
{
15+
private readonly IServiceProvider _serviceProvider;
16+
17+
public ControllerService(IServiceProvider serviceProvider)
18+
{
19+
_serviceProvider = serviceProvider;
20+
}
21+
22+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
23+
{
24+
var controllers = _serviceProvider.GetServices<IController>();
25+
await Task.WhenAll(controllers.Select(x => x.Initialize(stoppingToken)));
26+
}
27+
28+
}
29+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reactive.Disposables;
5+
using System.Reactive.Linq;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using k8s;
10+
using k8s.Informers;
11+
using k8s.Informers.Notifications;
12+
using k8s.Models;
13+
using KellermanSoftware.CompareNetObjects;
14+
using Microsoft.Extensions.Logging;
15+
16+
namespace informers
17+
{
18+
// this sample demos of informer in a basic controller context.
19+
// there are two loggers:
20+
// _informerLogger lets you see raw data coming out of informer stream
21+
22+
// try creating and deleting some pods in "default" namespace and watch the output
23+
// current code is not production grade and lacks concurrency guards against modifying same resource
24+
public class DeltaChangesQueryingController : IController
25+
{
26+
private readonly IKubernetesInformer<V1Pod> _podInformer;
27+
private readonly CompositeDisposable _subscription = new CompositeDisposable();
28+
private readonly ILogger _informerLogger;
29+
private readonly CompareLogic _objectCompare = new CompareLogic();
30+
31+
public DeltaChangesQueryingController(IKubernetesInformer<V1Pod> podInformer, ILoggerFactory loggerFactory)
32+
{
33+
_podInformer = podInformer;
34+
_informerLogger = loggerFactory.CreateLogger("Informer");
35+
_objectCompare.Config.MaxDifferences = 100;
36+
}
37+
38+
39+
public Task Initialize(CancellationToken cancellationToken)
40+
{
41+
_podInformer
42+
.GetResource(ResourceStreamType.ListWatch, KubernetesInformerOptions.Builder.NamespaceEquals("default").Build())
43+
.Resync(TimeSpan.FromSeconds(10))
44+
.Catch<ResourceEvent<V1Pod>, Exception>(e =>
45+
{
46+
_informerLogger.LogCritical(e, e.Message);
47+
return Observable.Throw<ResourceEvent<V1Pod>>(e);
48+
})
49+
.Buffer(TimeSpan.FromSeconds(5))
50+
.Where(x => x.Any())
51+
.Do(x =>
52+
{
53+
var eventsPerResource = x.GroupBy(x => x.Value.Metadata.Name);
54+
foreach (var item in eventsPerResource)
55+
{
56+
PrintChanges(item.ToList());
57+
}
58+
})
59+
.Subscribe()
60+
.DisposeWith(_subscription);
61+
return Task.CompletedTask;
62+
}
63+
64+
private void PrintChanges(IList<ResourceEvent<V1Pod>> changes)
65+
{
66+
// it's possible to do reconciliation here, but the current code is not production grade and lacks concurrency guards against modifying same resource
67+
var obj = changes.First().Value;
68+
var sb = new StringBuilder();
69+
sb.AppendLine($"Received changes for object with ID {obj.Metadata.Name} with {changes.Count} items");
70+
sb.AppendLine($"Last known state was {changes.Last().EventFlags}");
71+
foreach (var item in changes)
72+
{
73+
sb.AppendLine($"==={item.EventFlags}===");
74+
sb.AppendLine($"Name: {item.Value.Metadata.Name}");
75+
sb.AppendLine($"Version: {item.Value.Metadata.ResourceVersion}");
76+
if (item.EventFlags.HasFlag(EventTypeFlags.Modify))
77+
{
78+
var updateDelta = _objectCompare.Compare(item.OldValue, item.Value);
79+
foreach (var difference in updateDelta.Differences) sb.AppendLine($"{difference.PropertyName}: {difference.Object1} -> {difference.Object2}");
80+
}
81+
}
82+
83+
_informerLogger.LogInformation(sb.ToString());
84+
85+
}
86+
}
87+
}

examples/informers/IController.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace informers
5+
{
6+
/// <summary>
7+
/// Base interface for implementing controllers
8+
/// </summary>
9+
public interface IController
10+
{
11+
/// <summary>
12+
/// Signals that controller is done processing all the work and no more work will ever be processed.
13+
/// Mainly useful in testing
14+
/// </summary>
15+
public Task Initialize(CancellationToken cancellationToken);
16+
}
17+
}

examples/informers/Program.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Linq;
3+
using k8s;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Hosting;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace informers
9+
{
10+
public class Program
11+
{
12+
public static void Main(string[] args)
13+
{
14+
CreateHostBuilder(args).Build().Run();
15+
}
16+
17+
public static IHostBuilder CreateHostBuilder(string[] args) =>
18+
Host.CreateDefaultBuilder(args)
19+
.ConfigureLogging(x => x.AddConsole())
20+
.ConfigureServices((hostContext, services) =>
21+
{
22+
services.AddKubernetesClient(KubernetesClientConfiguration.BuildDefaultConfig);
23+
services.AddKubernetesInformers();
24+
25+
services.AddHostedService<ControllerService>();
26+
services.AddSingleton<IController, DeltaChangesQueryingController>();
27+
});
28+
}
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"profiles": {
3+
"K8SControllerExample": {
4+
"commandName": "Project",
5+
"environmentVariables": {
6+
"DOTNET_ENVIRONMENT": "Development"
7+
}
8+
}
9+
}
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}

examples/informers/appsettings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}

examples/informers/informers.csproj

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Worker">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<SignAssembly>true</SignAssembly>
6+
<AssemblyOriginatorKeyFile>..\..\src\KubernetesClient\kubernetes-client.snk</AssemblyOriginatorKeyFile>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="CompareNETObjects" Version="4.65.0" />
11+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.2" />
12+
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.2" />
13+
<PackageReference Include="NMica" Version="2.0.2" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\..\src\KubernetesClient.DependencyInjection\KubernetesClient.DependencyInjection.csproj" />
18+
</ItemGroup>
19+
</Project>

kubernetes-client.sln

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "patch", "examples\patch\pat
3535
EndProject
3636
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpClientFactory", "examples\httpClientFactory\httpClientFactory.csproj", "{A07314A0-02E8-4F36-B233-726D59D28F08}"
3737
EndProject
38+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "informers", "examples\informers\informers.csproj", "{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}"
39+
EndProject
40+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Informers", "src\KubernetesClient.Informers\KubernetesClient.Informers.csproj", "{7C1B2872-A0E3-4437-9532-0227F419399C}"
41+
EndProject
42+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Informers.Tests", "tests\KubernetesClient.Informers.Tests\KubernetesClient.Informers.Tests.csproj", "{5116C7E7-66A8-4523-AE5A-4CF00391C399}"
43+
EndProject
44+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.DependencyInjection", "src\KubernetesClient.DependencyInjection\KubernetesClient.DependencyInjection.csproj", "{5832A440-3DD9-47A4-8D3C-1FB049978297}"
45+
EndProject
3846
Global
3947
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4048
Debug|Any CPU = Debug|Any CPU
@@ -189,6 +197,54 @@ Global
189197
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x64.Build.0 = Release|Any CPU
190198
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x86.ActiveCfg = Release|Any CPU
191199
{A07314A0-02E8-4F36-B233-726D59D28F08}.Release|x86.Build.0 = Release|Any CPU
200+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
201+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
202+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|x64.ActiveCfg = Debug|Any CPU
203+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|x64.Build.0 = Debug|Any CPU
204+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|x86.ActiveCfg = Debug|Any CPU
205+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Debug|x86.Build.0 = Debug|Any CPU
206+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
207+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|Any CPU.Build.0 = Release|Any CPU
208+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|x64.ActiveCfg = Release|Any CPU
209+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|x64.Build.0 = Release|Any CPU
210+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|x86.ActiveCfg = Release|Any CPU
211+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2}.Release|x86.Build.0 = Release|Any CPU
212+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
213+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|Any CPU.Build.0 = Debug|Any CPU
214+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|x64.ActiveCfg = Debug|Any CPU
215+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|x64.Build.0 = Debug|Any CPU
216+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|x86.ActiveCfg = Debug|Any CPU
217+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Debug|x86.Build.0 = Debug|Any CPU
218+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|Any CPU.ActiveCfg = Release|Any CPU
219+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|Any CPU.Build.0 = Release|Any CPU
220+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|x64.ActiveCfg = Release|Any CPU
221+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|x64.Build.0 = Release|Any CPU
222+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|x86.ActiveCfg = Release|Any CPU
223+
{7C1B2872-A0E3-4437-9532-0227F419399C}.Release|x86.Build.0 = Release|Any CPU
224+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
225+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|Any CPU.Build.0 = Debug|Any CPU
226+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|x64.ActiveCfg = Debug|Any CPU
227+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|x64.Build.0 = Debug|Any CPU
228+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|x86.ActiveCfg = Debug|Any CPU
229+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Debug|x86.Build.0 = Debug|Any CPU
230+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|Any CPU.ActiveCfg = Release|Any CPU
231+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|Any CPU.Build.0 = Release|Any CPU
232+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|x64.ActiveCfg = Release|Any CPU
233+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|x64.Build.0 = Release|Any CPU
234+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|x86.ActiveCfg = Release|Any CPU
235+
{5116C7E7-66A8-4523-AE5A-4CF00391C399}.Release|x86.Build.0 = Release|Any CPU
236+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
237+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|Any CPU.Build.0 = Debug|Any CPU
238+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|x64.ActiveCfg = Debug|Any CPU
239+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|x64.Build.0 = Debug|Any CPU
240+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|x86.ActiveCfg = Debug|Any CPU
241+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Debug|x86.Build.0 = Debug|Any CPU
242+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|Any CPU.ActiveCfg = Release|Any CPU
243+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|Any CPU.Build.0 = Release|Any CPU
244+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|x64.ActiveCfg = Release|Any CPU
245+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|x64.Build.0 = Release|Any CPU
246+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|x86.ActiveCfg = Release|Any CPU
247+
{5832A440-3DD9-47A4-8D3C-1FB049978297}.Release|x86.Build.0 = Release|Any CPU
192248
EndGlobalSection
193249
GlobalSection(SolutionProperties) = preSolution
194250
HideSolutionNode = FALSE
@@ -206,6 +262,10 @@ Global
206262
{542DC30E-FDF7-4A35-B026-6C21F435E8B1} = {879F8787-C3BB-43F3-A92D-6D4C7D3A5285}
207263
{04DE2C84-117D-4E21-8B45-B7AE627697BD} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
208264
{A07314A0-02E8-4F36-B233-726D59D28F08} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
265+
{A24E81F3-EFB1-4AFE-8C87-BDF2D3A0C0C2} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
266+
{7C1B2872-A0E3-4437-9532-0227F419399C} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
267+
{5116C7E7-66A8-4523-AE5A-4CF00391C399} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
268+
{5832A440-3DD9-47A4-8D3C-1FB049978297} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
209269
EndGlobalSection
210270
GlobalSection(ExtensibilityGlobals) = postSolution
211271
SolutionGuid = {049A763A-C891-4E8D-80CF-89DD3E22ADC7}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Authors>The Kubernetes Project Authors</Authors>
5+
<Copyright>2017 The Kubernetes Project Authors</Copyright>
6+
<Description>Client library for the Kubernetes open source container orchestrator.</Description>
7+
8+
<PackageLicenseUrl>https://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
9+
<PackageProjectUrl>https://github.com/kubernetes-client/csharp</PackageProjectUrl>
10+
<PackageIconUrl>https://raw.githubusercontent.com/kubernetes/kubernetes/master/logo/logo.png</PackageIconUrl>
11+
<PackageTags>kubernetes;docker;containers;</PackageTags>
12+
<TargetFrameworks>netstandard2.0</TargetFrameworks>
13+
<RootNamespace>k8s</RootNamespace>
14+
<SignAssembly>true</SignAssembly>
15+
<AssemblyOriginatorKeyFile>..\KubernetesClient\kubernetes-client.snk</AssemblyOriginatorKeyFile>
16+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
17+
<NoWarn>1701;1702;1591;1570;1572;1573;1574</NoWarn>
18+
19+
<!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
20+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
21+
22+
<!-- Build symbol package (.snupkg) to distribute the PDB containing Source Link -->
23+
<IncludeSymbols>true</IncludeSymbols>
24+
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
25+
<LangVersion>8</LangVersion>
26+
</PropertyGroup>
27+
28+
<ItemGroup>
29+
<PackageReference Include="Nerdbank.GitVersioning" Version="3.1.74" PrivateAssets="all" />
30+
31+
<ProjectReference Include="..\KubernetesClient.Informers\KubernetesClient.Informers.csproj" />
32+
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.2" />
33+
</ItemGroup>
34+
35+
</Project>

0 commit comments

Comments
 (0)