Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
34ace26
refactor: update controller and finalizer interfaces to return `Resul…
kimpenhaus Jun 4, 2025
fddb472
Merge branch 'main' into result-pattern
kimpenhaus Jun 4, 2025
ac36c04
refactor: update controller and finalizer interfaces to return `Resul…
kimpenhaus Jun 4, 2025
e67f7b7
Merge remote-tracking branch 'origin/result-pattern' into result-pattern
kimpenhaus Jun 17, 2025
d31a132
refactor: mark `OperatorBuilderGenerator` as `sealed` and use constan…
kimpenhaus Jun 27, 2025
5e00fa3
feat: add FusionCache for resource watcher to enable L1 and L2 cachin…
kimpenhaus Jun 27, 2025
6d8def6
refactor: optimize resource watcher cache handling and remove redunda…
kimpenhaus Jun 30, 2025
3d2e607
refactor: enhance resource watcher cache configuration and logging scope
kimpenhaus Jul 1, 2025
f184048
refactor: rename cache extension methods and adjust visibility
kimpenhaus Jul 1, 2025
9bcf9c0
Merge branch 'buehler:main' into entity_cache
kimpenhaus Jul 7, 2025
5e4de87
refactor: update cache key prefix in `CacheExtensions` to use `CacheC…
kimpenhaus Jul 7, 2025
a8f2ba3
Merge remote-tracking branch 'origin/entity_cache' into entity_cache
kimpenhaus Jul 7, 2025
8ce68a8
docs: add caching documentation and adjust sidebar positions
kimpenhaus Jul 7, 2025
2a6f4fc
docs: enhance caching documentation with configuration examples and F…
kimpenhaus Jul 7, 2025
275878b
Merge branch 'buehler:main' into result-pattern
kimpenhaus Jul 9, 2025
66eef75
Merge branch 'entity_cache' into result-pattern
kimpenhaus Jul 9, 2025
d83914a
Merge branch 'main' into result-pattern
kimpenhaus Aug 19, 2025
1ad141c
refactor(watcher): streamline deletion logic and update FusionCache d…
kimpenhaus Sep 5, 2025
6ded18f
refactor(operator): remove unused FusionCache dependency from project…
kimpenhaus Sep 5, 2025
9dce9df
feat(queue): add `RequeueType` and enhance requeue handling
kimpenhaus Sep 8, 2025
12aeda4
refactor(reconciliation): introduce `Reconciler` to centralize entity…
kimpenhaus Sep 10, 2025
a9c122c
Merge branch 'dotnet:main' into result-pattern
kimpenhaus Sep 10, 2025
f1d20f6
feat(operator): add `IReconciler` registration in `OperatorBuilder`
kimpenhaus Sep 10, 2025
4fc59eb
feat(reconciler): enhance finalizer management with configurable auto…
kimpenhaus Sep 11, 2025
fda45f2
refactor(generator): enhance syntax model resolution to support const…
kimpenhaus Sep 12, 2025
e875b83
feat(finalizer): fix identifier generation and add unit tests
kimpenhaus Sep 12, 2025
84d97ef
test(finalizer): update and expand unit tests for entity finalizers
kimpenhaus Sep 12, 2025
d6d4b34
refactor(result): make `ErrorMessage` readonly and allow setting `Req…
kimpenhaus Sep 15, 2025
5c935aa
refactor(queue): replace `TimedEntityQueue` with `ITimedEntityQueue` …
kimpenhaus Sep 15, 2025
b222cac
feat(operator): introduce `LeaderElectionType` for configurable leade…
kimpenhaus Sep 15, 2025
88180ed
refactor(operator): expose `Settings` in `OperatorBuilder` and update…
kimpenhaus Sep 16, 2025
9bee002
feat(queue): add logging to `TimedEntityQueue` and update test implem…
kimpenhaus Sep 16, 2025
54c59b3
refactor(admission): seal `AdmissionStatus` and `MutationResult`; upd…
kimpenhaus Sep 23, 2025
152a5aa
Merge branch 'dotnet:main' into result-pattern
kimpenhaus Sep 23, 2025
d48c2a5
refactor(reconciliation): migrate `Result` to `ReconciliationResult` …
kimpenhaus Sep 24, 2025
f9aa5cf
Merge remote-tracking branch 'origin/result-pattern' into result-pattern
kimpenhaus Sep 24, 2025
415473c
refactor(syntax-receiver): update metadata names to reflect new recon…
kimpenhaus Sep 24, 2025
9df73fc
refactor(reconciliation): update imports to reflect new `Reconciliati…
kimpenhaus Sep 24, 2025
4f000e9
fix(reconciliation): ensure finalizers are executed for entities mark…
kimpenhaus Sep 24, 2025
d21719e
feat(watcher): integrate `FusionCache` for bookmark version caching i…
kimpenhaus Sep 25, 2025
c3b3af0
refactor(watcher): remove `FusionCache` usage for bookmark version ha…
kimpenhaus Sep 25, 2025
2e21cb8
refactor(watcher): remove `FusionCache` dependency in `LeaderAwareRes…
kimpenhaus Sep 25, 2025
5f5f3e8
feat(reconciliation): introduce `ReconciliationContext` and trigger s…
kimpenhaus Oct 2, 2025
efa9a91
refactor(queue): make `Enqueue` and `Remove` methods asynchronous
kimpenhaus Oct 10, 2025
b215401
refactor(queue): add `CancellationToken` support for `Enqueue` and `R…
kimpenhaus Oct 10, 2025
5bd1a77
Merge branch 'dotnet:main' into result-pattern
kimpenhaus Oct 20, 2025
daeba95
refactor(queue): remove unused `Reconciliation` import in `EntityRequ…
kimpenhaus Oct 21, 2025
24f2ca7
refactor(queue): add `JsonConstructor` to `RequeueEntry`
kimpenhaus Oct 21, 2025
299f24e
Merge branch 'dotnet:main' into result-pattern
kimpenhaus Oct 29, 2025
5b0fc66
refactor(reconciliation): consolidate event-specific reconciliation m…
kimpenhaus Oct 30, 2025
254b646
refactor(tests): remove unused `Reconciliation` folder entry from `.c…
kimpenhaus Oct 30, 2025
a6e01ba
refactor(docs): update reconciliation methods and examples to use `Re…
kimpenhaus Oct 30, 2025
53b2513
docs(operator): add advanced configuration guide and update related s…
kimpenhaus Oct 30, 2025
515d4cd
test: add comprehensive unit tests for reconciliation and queue logic
kimpenhaus Oct 30, 2025
8bd859b
test: extend reconciliation tests with finalizer handling and caching…
kimpenhaus Oct 30, 2025
1ceb116
test: exclude test projects from code coverage analysis
kimpenhaus Oct 30, 2025
7a65fed
chore(deps): upgrade `KubernetesClient` to version `18.0.5`
kimpenhaus Oct 29, 2025
014a335
refactor: update object initialization to use object initializer shor…
kimpenhaus Oct 31, 2025
464730a
refactor: apply object initializer shorthand and seal generator classes
kimpenhaus Oct 31, 2025
a8a1366
refactor: mark entities and tests as `sealed`, add null checks in fin…
kimpenhaus Oct 31, 2025
812252c
refactor: adjust formatting for consistency and readability across te…
kimpenhaus Oct 31, 2025
ed5c140
refactor: fixed whitespace formatting
kimpenhaus Oct 31, 2025
91f1caa
Merge branch 'k8s-client-v18' into result-pattern
kimpenhaus Oct 31, 2025
58ea528
chore: add Apache 2.0 license headers and improve readability
kimpenhaus Oct 31, 2025
1e63804
docs: remove details in finalizer configuration guide
kimpenhaus Oct 31, 2025
18450f6
docs: update advanced configuration guide with time synchronization tip
kimpenhaus Oct 31, 2025
42ea861
refactor: improve naming consistency
kimpenhaus Nov 3, 2025
b744026
Merge branch 'dotnet:main' into result-pattern
kimpenhaus Nov 4, 2025
067a773
try to fix CodeQL recommendations: https://codeql.github.com/codeql-q…
kimpenhaus Nov 4, 2025
17944e9
restore finalizer integration tests with new configuration options
kimpenhaus Nov 4, 2025
8bc4345
fixed `No service for type` test issues
kimpenhaus Nov 4, 2025
1289fa7
reconcile: move `Remove` calls to specific reconciliation methods
kimpenhaus Nov 4, 2025
cb78196
Merge branch 'main' into result-pattern
kimpenhaus Nov 9, 2025
9824d93
refactor: enforce `sealed` keyword for entity-related classes and upd…
kimpenhaus Nov 12, 2025
fe6ba3f
refactor: remove `IsFailure` property in favor of `!IsSuccess` usage
kimpenhaus Nov 12, 2025
7dadcbd
chore: updated readme.md to latest changes
kimpenhaus Nov 12, 2025
0e01663
refactor: remove `InternalsVisibleTo` attribute from AssemblyInfo.cs
kimpenhaus Nov 12, 2025
c4358a9
log: upgrade log level from Debug to Warning for missing finalizer sc…
kimpenhaus Nov 13, 2025
f19ca77
refactor: update `RequeueEntry` and `TimedQueueEntry` to improve init…
kimpenhaus Nov 13, 2025
6466988
refactor: replace factory method in `RequeueEntry` with object initia…
kimpenhaus Nov 13, 2025
dbc8643
refactor: add requeue strategy support and improve contextual logging…
kimpenhaus Nov 14, 2025
6c5ef30
refactor: simplify `TryAdd` call in `TimedQueueEntry` with compact ob…
kimpenhaus Nov 14, 2025
6f3f48d
refactor: convert `RequeueEntry` to readonly record struct for improv…
kimpenhaus Nov 14, 2025
84fe20b
Merge branch 'main' into result-pattern
kimpenhaus Nov 14, 2025
d1b285f
log: downgrade log level from Warning to Information for missing fina…
kimpenhaus Nov 14, 2025
e5a5fb8
Merge branch 'main' into result-pattern
kimpenhaus Nov 20, 2025
d4aa7b8
Merge branch 'main' into result-pattern
kimpenhaus Nov 20, 2025
310307e
Merge branch 'main' into result-pattern
kimpenhaus Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: update controller and finalizer interfaces to return `Resul…
…t<TEntity>`
  • Loading branch information
kimpenhaus committed Jun 17, 2025
commit ac36c0489beabd56b2e98494c9db9e746361cf23
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ namespace ConversionWebhookOperator.Controller;
[EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]
public class V1TestEntityController(ILogger<V1TestEntityController> logger) : IEntityController<V1TestEntity>
{
public Task ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Reconciling entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}

public Task DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Deleted entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}
}
10 changes: 5 additions & 5 deletions examples/Operator/Controller/V1TestEntityController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
namespace Operator.Controller;

[EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]
public class V1TestEntityController(ILogger<V1TestEntityController> logger)
public sealed class V1TestEntityController(ILogger<V1TestEntityController> logger)
: IEntityController<V1TestEntity>
{
public Task ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Reconciling entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}

public Task DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Deleting entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}
}
11 changes: 5 additions & 6 deletions examples/Operator/Finalizer/FinalizerOne.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using KubeOps.Abstractions.Finalizer;
using KubeOps.Abstractions.Controller;
using KubeOps.Abstractions.Finalizer;

using Operator.Entities;

namespace Operator.Finalizer;

public class FinalizerOne : IEntityFinalizer<V1TestEntity>
public sealed class FinalizerOne : IEntityFinalizer<V1TestEntity>
{
public Task FinalizeAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public Task<Result<V1TestEntity>> FinalizeAsync(V1TestEntity entity, CancellationToken cancellationToken)
=> Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}
10 changes: 5 additions & 5 deletions examples/WebhookOperator/Controller/V1TestEntityController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
namespace WebhookOperator.Controller;

[EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]
public class V1TestEntityController(ILogger<V1TestEntityController> logger) : IEntityController<V1TestEntity>
public sealed class V1TestEntityController(ILogger<V1TestEntityController> logger) : IEntityController<V1TestEntity>
{
public Task ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> ReconcileAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Reconciling entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}

public Task DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
public Task<Result<V1TestEntity>> DeletedAsync(V1TestEntity entity, CancellationToken cancellationToken)
{
logger.LogInformation("Deleted entity {Entity}.", entity);
return Task.CompletedTask;
return Task.FromResult(Result<V1TestEntity>.ForSuccess(entity));
}
}
19 changes: 9 additions & 10 deletions src/KubeOps.Abstractions/Controller/IEntityController{TEntity}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,23 @@ namespace KubeOps.Abstractions.Controller;
/// }
/// </code>
/// </example>
public interface IEntityController<in TEntity>
public interface IEntityController<TEntity>
where TEntity : IKubernetesObject<V1ObjectMeta>
{
/// <summary>
/// Called for `added` and `modified` events from the watcher.
/// Reconciles the state of the specified entity with the desired state.
/// This method is triggered for `added` and `modified` events from the watcher.
/// </summary>
/// <param name="entity">The entity that fired the reconcile event.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task that completes when the reconciliation is done.</returns>
Task ReconcileAsync(TEntity entity, CancellationToken cancellationToken);
/// <param name="entity">The entity that initiated the reconcile operation.</param>
/// <param name="cancellationToken">The token used to signal cancellation of the operation.</param>
/// <returns>A task that represents the asynchronous operation and contains the result of the reconcile process.</returns>
Task<Result<TEntity>> ReconcileAsync(TEntity entity, CancellationToken cancellationToken);

/// <summary>
/// Called for `delete` events for a given entity.
/// </summary>
/// <param name="entity">The entity that fired the deleted event.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>
/// A task that completes, when the reconciliation is done.
/// </returns>
Task DeletedAsync(TEntity entity, CancellationToken cancellationToken);
/// <returns>A task that represents the asynchronous operation and contains the result of the reconcile process.</returns>
Task<Result<TEntity>> DeletedAsync(TEntity entity, CancellationToken cancellationToken);
}
43 changes: 43 additions & 0 deletions src/KubeOps.Abstractions/Controller/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Diagnostics.CodeAnalysis;

using k8s;
using k8s.Models;

namespace KubeOps.Abstractions.Controller;

public sealed record Result<TEntity>
where TEntity : IKubernetesObject<V1ObjectMeta>
{
private Result(TEntity entity, bool isSuccess, string? errorMessage, Exception? error, TimeSpan? requeueAfter)
{
Entity = entity;
IsSuccess = isSuccess;
ErrorMessage = errorMessage;
Error = error;
RequeueAfter = requeueAfter;
}

public TEntity Entity { get; }

[MemberNotNullWhen(false, nameof(ErrorMessage))]
public bool IsSuccess { get; }

[MemberNotNullWhen(true, nameof(ErrorMessage))]
public bool IsFailure => !IsSuccess;

public string? ErrorMessage { get; set; }

public Exception? Error { get; }

public TimeSpan? RequeueAfter { get; }

public static Result<TEntity> ForSuccess(TEntity entity, TimeSpan? requeueAfter = null)
{
return new(entity, true, null, null, requeueAfter);
}

public static Result<TEntity> ForFailure(TEntity entity, string errorMessage, Exception? error = null, TimeSpan? requeueAfter = null)
{
return new(entity, false, errorMessage, error, requeueAfter);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
using k8s;
using k8s.Models;

using KubeOps.Abstractions.Controller;

namespace KubeOps.Abstractions.Finalizer;

/// <summary>
/// Finalizer for an entity.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
public interface IEntityFinalizer<in TEntity>
public interface IEntityFinalizer<TEntity>
where TEntity : IKubernetesObject<V1ObjectMeta>
{
/// <summary>
/// Finalize an entity that is pending for deletion.
/// </summary>
/// <param name="entity">The kubernetes entity that needs to be finalized.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task that resolves when the operation is done.</returns>
Task FinalizeAsync(TEntity entity, CancellationToken cancellationToken);
/// <returns>A task that represents the asynchronous operation and contains the result of the reconcile process.</returns>
Task<Result<TEntity>> FinalizeAsync(TEntity entity, CancellationToken cancellationToken);
}
3 changes: 2 additions & 1 deletion src/KubeOps.Abstractions/KubeOps.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

<ItemGroup>
<PackageReference Include="KubernetesClient" Version="16.0.7" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.6"/>
</ItemGroup>

</Project>
</Project>
2 changes: 1 addition & 1 deletion src/KubeOps.Abstractions/Queue/EntityRequeue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ namespace KubeOps.Abstractions.Queue;
/// }
/// </code>
/// </example>
public delegate void EntityRequeue<TEntity>(TEntity entity, TimeSpan requeueIn)
public delegate void EntityRequeue<in TEntity>(TEntity entity, TimeSpan requeueIn)
where TEntity : IKubernetesObject<V1ObjectMeta>;
20 changes: 17 additions & 3 deletions src/KubeOps.Operator/Queue/EntityRequeueBackgroundService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using k8s.Models;

using KubeOps.Abstractions.Controller;
using KubeOps.Abstractions.Finalizer;
using KubeOps.KubernetesClient;

using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -118,8 +119,21 @@ private async Task ReconcileSingleAsync(TEntity queued, CancellationToken cancel
return;
}

await using var scope = provider.CreateAsyncScope();
var controller = scope.ServiceProvider.GetRequiredService<IEntityController<TEntity>>();
await controller.ReconcileAsync(entity, cancellationToken);
if (entity.DeletionTimestamp() is not null)
{
if (entity.Finalizers()?.Count > 0)
{
var identifier = entity.Finalizers()[0];
await using var scope = provider.CreateAsyncScope();
var finalizer = scope.ServiceProvider.GetRequiredKeyedService<IEntityFinalizer<TEntity>>(identifier);
await finalizer.FinalizeAsync(entity, cancellationToken);
}
}
else
{
await using var scope = provider.CreateAsyncScope();
var controller = scope.ServiceProvider.GetRequiredService<IEntityController<TEntity>>();
await controller.ReconcileAsync(entity, cancellationToken);
}
}
}
Loading