From 5cd5da85ab2f7c3d89fa4e4a8166db9c2c8a66ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Wed, 4 Oct 2023 16:28:57 +0200 Subject: [PATCH] chore: remove old code --- .../Operator/Caching/CacheComparisonResult.cs | 36 --- .../Operator/Caching/IResourceCache.cs | 18 -- .../Caching/ResourceCache{TEntity}.cs | 112 -------- .../Controller/ControllerInstanceBuilder.cs | 33 --- .../KubeOps/Operator/Controller/EventQueue.cs | 238 ----------------- .../Controller/IControllerInstanceBuilder.cs | 18 -- .../Operator/Controller/IEventQueue.cs | 16 -- .../Controller/IManagedResourceController.cs | 8 - .../IResourceController{TEntity}.cs | 48 ---- .../ManagedResourceController{TEntity}.cs | 251 ------------------ .../Controller/ResourceControllerManager.cs | 64 ----- .../Operator/Controller/ResourceEvent.cs | 9 - .../Controller/Results/RequeueEventResult.cs | 16 -- .../Results/ResourceControllerResult.cs | 63 ----- .../Controller/ScopedResourceController.cs | 19 -- .../Entities/CustomKubernetesEntity.cs | 15 -- .../CustomKubernetesEntity{TSpec,TStatus}.cs | 21 -- .../Entities/CustomKubernetesEntity{TSpec}.cs | 17 -- .../KubeOps/Operator/Entities/EntityList.cs | 22 -- .../Finalizer/FinalizerInstanceBuilder.cs | 32 --- .../Finalizer/FinalizerManager{TEntity}.cs | 124 --------- .../Finalizer/IFinalizerInstanceBuilder.cs | 13 - .../Finalizer/IFinalizerManager{TEntity}.cs | 40 --- .../Operator/Finalizer/IResourceFinalizer.cs | 42 --- .../src/KubeOps/Operator/HashSetExtensions.cs | 24 -- _old/src/KubeOps/Operator/HostExtensions.cs | 39 --- .../Operator/Kubernetes/IResourceWatcher.cs | 14 - .../Operator/Kubernetes/ResourceEventType.cs | 32 --- .../Kubernetes/ResourceWatcher{TEntity}.cs | 243 ----------------- .../Operator/OperatorBuilderExtensions.cs | 167 ------------ .../Operator/Rbac/EntityRbacAttribute.cs | 29 -- .../Operator/Rbac/GenericRbacAttribute.cs | 41 --- .../src/KubeOps/Operator/Rbac/IRbacBuilder.cs | 8 - .../Operator/Rbac/RbacAttributeExtensions.cs | 111 -------- _old/src/KubeOps/Operator/Rbac/RbacBuilder.cs | 103 ------- _old/src/KubeOps/Operator/Rbac/RbacVerbs.cs | 53 ---- .../Serialization/EntitySerializer.cs | 14 - .../Serialization/SerializerOutputFormat.cs | 14 - .../Operator/ServiceCollectionExtensions.cs | 36 --- .../KubeOps/Operator/Util/StringExtensions.cs | 28 -- 40 files changed, 2231 deletions(-) delete mode 100644 _old/src/KubeOps/Operator/Caching/CacheComparisonResult.cs delete mode 100644 _old/src/KubeOps/Operator/Caching/IResourceCache.cs delete mode 100644 _old/src/KubeOps/Operator/Caching/ResourceCache{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/ControllerInstanceBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/EventQueue.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/IControllerInstanceBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/IEventQueue.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/IManagedResourceController.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/IResourceController{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/ManagedResourceController{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/ResourceControllerManager.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/ResourceEvent.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/Results/RequeueEventResult.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/Results/ResourceControllerResult.cs delete mode 100644 _old/src/KubeOps/Operator/Controller/ScopedResourceController.cs delete mode 100644 _old/src/KubeOps/Operator/Entities/CustomKubernetesEntity.cs delete mode 100644 _old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec,TStatus}.cs delete mode 100644 _old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec}.cs delete mode 100644 _old/src/KubeOps/Operator/Entities/EntityList.cs delete mode 100644 _old/src/KubeOps/Operator/Finalizer/FinalizerInstanceBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Finalizer/FinalizerManager{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/Finalizer/IFinalizerInstanceBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Finalizer/IFinalizerManager{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/Finalizer/IResourceFinalizer.cs delete mode 100644 _old/src/KubeOps/Operator/HashSetExtensions.cs delete mode 100644 _old/src/KubeOps/Operator/HostExtensions.cs delete mode 100644 _old/src/KubeOps/Operator/Kubernetes/IResourceWatcher.cs delete mode 100644 _old/src/KubeOps/Operator/Kubernetes/ResourceEventType.cs delete mode 100644 _old/src/KubeOps/Operator/Kubernetes/ResourceWatcher{TEntity}.cs delete mode 100644 _old/src/KubeOps/Operator/OperatorBuilderExtensions.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/EntityRbacAttribute.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/GenericRbacAttribute.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/IRbacBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/RbacAttributeExtensions.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/RbacBuilder.cs delete mode 100644 _old/src/KubeOps/Operator/Rbac/RbacVerbs.cs delete mode 100644 _old/src/KubeOps/Operator/Serialization/EntitySerializer.cs delete mode 100644 _old/src/KubeOps/Operator/Serialization/SerializerOutputFormat.cs delete mode 100644 _old/src/KubeOps/Operator/ServiceCollectionExtensions.cs delete mode 100644 _old/src/KubeOps/Operator/Util/StringExtensions.cs diff --git a/_old/src/KubeOps/Operator/Caching/CacheComparisonResult.cs b/_old/src/KubeOps/Operator/Caching/CacheComparisonResult.cs deleted file mode 100644 index 7a8cac18..00000000 --- a/_old/src/KubeOps/Operator/Caching/CacheComparisonResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace KubeOps.Operator.Caching; - -/// -/// Result for the when comparison is done. -/// -internal enum CacheComparisonResult -{ - /// - /// - /// The resource is either: - /// - /// - /// New to the cache - /// - /// - /// Modified - /// - /// - /// Not Modified - /// - /// - /// - /// But not status or finalizer modified. This is used to reconcile objects. - /// - Other, - - /// - /// The resource has changed, but only the "status" of it. - /// - StatusModified, - - /// - /// The resource has changed, but only the "finalizers" list. - /// - FinalizersModified, -} diff --git a/_old/src/KubeOps/Operator/Caching/IResourceCache.cs b/_old/src/KubeOps/Operator/Caching/IResourceCache.cs deleted file mode 100644 index 24a68345..00000000 --- a/_old/src/KubeOps/Operator/Caching/IResourceCache.cs +++ /dev/null @@ -1,18 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Caching; - -internal interface IResourceCache - where TEntity : IKubernetesObject -{ - TEntity Get(string id); - - TEntity Upsert(TEntity resource, out CacheComparisonResult result); - - void Fill(IEnumerable resources); - - void Remove(TEntity resource); - - void Clear(); -} diff --git a/_old/src/KubeOps/Operator/Caching/ResourceCache{TEntity}.cs b/_old/src/KubeOps/Operator/Caching/ResourceCache{TEntity}.cs deleted file mode 100644 index a52908d1..00000000 --- a/_old/src/KubeOps/Operator/Caching/ResourceCache{TEntity}.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Collections.Concurrent; - -using k8s; -using k8s.Models; - -using KellermanSoftware.CompareNetObjects; - -using KubeOps.Operator.DevOps; -using KubeOps.Operator.Entities.Extensions; - -namespace KubeOps.Operator.Caching; - -internal class ResourceCache : IResourceCache - where TEntity : IKubernetesObject -{ - private const string Finalizers = "Metadata.Finalizers"; - private const string Status = "Status"; - - private readonly CompareLogic _compare; - - private readonly ConcurrentDictionary _cache = new(); - - private readonly ResourceCacheMetrics _metrics; - - public ResourceCache(ResourceCacheMetrics metrics, OperatorSettings settings) - { - _metrics = metrics; - - _compare = new CompareLogic(settings.CacheComparisonConfig); - } - - public TEntity Get(string id) => _cache[id]; - - public TEntity Upsert(TEntity resource, out CacheComparisonResult result) - { - result = CompareCache(resource); - - var clone = resource.DeepClone(); - if (clone == null) - { - throw new ArgumentNullException(nameof(clone)); - } - - _cache.AddOrUpdate(resource.Metadata.Uid, clone, (_, _) => clone); - - _metrics.CachedItemsSize.Set(_cache.Count); - _metrics.CachedItemsSummary.Observe(_cache.Count); - return resource; - } - - public void Fill(IEnumerable resources) - { - foreach (var entity in resources) - { - var clone = entity.DeepClone(); - if (clone == null) - { - throw new ArgumentNullException(nameof(clone)); - } - - _cache.AddOrUpdate(entity.Metadata.Uid, clone, (_, _) => clone); - } - - _metrics.CachedItemsSize.Set(_cache.Count); - _metrics.CachedItemsSummary.Observe(_cache.Count); - } - - public void Remove(TEntity resource) => Remove(resource.Metadata.Uid); - - public void Clear() - { - _cache.Clear(); - _metrics.CachedItemsSize.Set(_cache.Count); - _metrics.CachedItemsSummary.Observe(_cache.Count); - } - - private CacheComparisonResult CompareCache(TEntity resource) - { - if (!Exists(resource)) - { - return CacheComparisonResult.Other; - } - - var cacheObject = _cache[resource.Metadata.Uid]; - var comparison = _compare.Compare(resource, cacheObject); - if (comparison.AreEqual) - { - return CacheComparisonResult.Other; - } - - if (comparison.Differences.All(d => d.PropertyName.Split('.')[0] == Status)) - { - return CacheComparisonResult.StatusModified; - } - - if (comparison.Differences.All(d => d.ParentPropertyName == Finalizers || d.PropertyName == Finalizers)) - { - return CacheComparisonResult.FinalizersModified; - } - - return CacheComparisonResult.Other; - } - - private bool Exists(TEntity resource) => _cache.ContainsKey(resource.Metadata.Uid); - - private void Remove(string resourceUid) - { - _cache.TryRemove(resourceUid, out _); - _metrics.CachedItemsSize.Set(_cache.Count); - _metrics.CachedItemsSummary.Observe(_cache.Count); - } -} diff --git a/_old/src/KubeOps/Operator/Controller/ControllerInstanceBuilder.cs b/_old/src/KubeOps/Operator/Controller/ControllerInstanceBuilder.cs deleted file mode 100644 index 8ab36805..00000000 --- a/_old/src/KubeOps/Operator/Controller/ControllerInstanceBuilder.cs +++ /dev/null @@ -1,33 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Builder; - -namespace KubeOps.Operator.Controller; - -internal class ControllerInstanceBuilder : IControllerInstanceBuilder -{ - private readonly IComponentRegistrar _componentRegistrar; - private readonly IControllerInstanceBuilder.ControllerFactory _controllerFactory; - private readonly IServiceProvider _serviceProvider; - - public ControllerInstanceBuilder( - IComponentRegistrar componentRegistrar, - IControllerInstanceBuilder.ControllerFactory controllerFactory, - IServiceProvider serviceProvider) - { - _componentRegistrar = componentRegistrar; - _controllerFactory = controllerFactory; - _serviceProvider = serviceProvider; - } - - public IEnumerable BuildControllers() - => _componentRegistrar.ControllerRegistrations - .Select(r => _controllerFactory.Invoke(_serviceProvider, r)); - - public IEnumerable BuildControllers() - where TEntity : IKubernetesObject - => _componentRegistrar.ControllerRegistrations - .For() - .Select(r => _controllerFactory.Invoke(_serviceProvider, r)); -} diff --git a/_old/src/KubeOps/Operator/Controller/EventQueue.cs b/_old/src/KubeOps/Operator/Controller/EventQueue.cs deleted file mode 100644 index 8582b0a5..00000000 --- a/_old/src/KubeOps/Operator/Controller/EventQueue.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System.Reactive.Linq; -using System.Reactive.Subjects; - -using k8s; -using k8s.Models; - -using KubeOps.KubernetesClient; -using KubeOps.Operator.Caching; -using KubeOps.Operator.Kubernetes; - -namespace KubeOps.Operator.Controller; - -internal class EventQueue : IEventQueue - where TEntity : class, IKubernetesObject -{ - private readonly IKubernetesClient _kubernetesClient; - private readonly ILogger> _logger; - private readonly OperatorSettings _operatorSettings; - private readonly IResourceCache _resourceCache; - private readonly IResourceWatcher _watcher; - - private readonly Subject> _localEvents; - private Action> _onWatcherEvent; - - public EventQueue( - IKubernetesClient kubernetesClient, - ILogger> logger, - OperatorSettings operatorSettings, - IResourceCache resourceCache, - IResourceWatcher watcher) - { - _kubernetesClient = kubernetesClient; - _logger = logger; - _operatorSettings = operatorSettings; - _resourceCache = resourceCache; - _watcher = watcher; - - _localEvents = new Subject>(); - _onWatcherEvent = _ => { }; - - var watcherEvents = _watcher - .WatchEvents - .Select(MapToResourceEvent) - .Do(_onWatcherEvent); - - Events = _localEvents - .Merge(watcherEvents) - .Where(EventRetryCountIsLessThanMax) - .GroupBy(e => e.Resource.Uid()) - .Select( - group => group - .Select(ProcessDelay) - .Switch()) - .Merge() - .Select(UpdateResourceData) - .Merge() - .Where(EventTypeIsNotFinalizerModified); - } - - public IObservable> Events { get; } - - public async Task StartAsync(Action> onWatcherEvent) - { - if (_operatorSettings.PreloadCache) - { - _logger.LogInformation("The 'preload cache' setting is set to 'true'."); - var items = await _kubernetesClient.List(_operatorSettings.Namespace); - _resourceCache.Fill(items); - } - - _onWatcherEvent = onWatcherEvent; - - await _watcher.StartAsync(); - } - - public async Task StopAsync() - { - await _watcher.StopAsync(); - } - - public void EnqueueLocal(ResourceEvent resourceEvent) => _localEvents.OnNext(resourceEvent); - - private static bool EventTypeIsNotFinalizerModified(ResourceEvent resourceEvent) => - resourceEvent.Type != ResourceEventType.FinalizerModified; - - private static IObservable> ProcessDelay( - ResourceEvent resourceEvent) - { - var delay = resourceEvent.Delay ?? TimeSpan.Zero; - return Observable.Return(resourceEvent).DelaySubscription(delay); - } - - private bool EventRetryCountIsLessThanMax(ResourceEvent resourceEvent) - { - (ResourceEventType type, TEntity resource, var attempt, TimeSpan? delay) = resourceEvent; - - if (attempt == 0) - { - return true; - } - - if (attempt <= _operatorSettings.MaxErrorRetries) - { - _logger.LogDebug( - @"Retry attempt {retryCount} for event ""{eventType}"" on resource ""{kind}/{name}"" with exponential backoff ""{backoff}"".", - attempt, - type, - resource.Kind, - resource.Name(), - delay); - return true; - } - - _logger.LogError( - @"Event ""{eventType}"" on resource ""{kind}/{name}"" threw too many errors. Skipping Event.", - resourceEvent, - resource.Kind, - resource.Name()); - - return false; - } - - private ResourceEvent MapToResourceEvent(ResourceWatcher.WatchEvent watchEvent) - { - (WatchEventType watchEventType, TEntity resource) = watchEvent; - ResourceEvent output; - - _logger.LogTrace( - @"Mapping watcher event ""{watchEvent}"" for ""{kind}/{name}"".", - watchEventType, - resource.Kind, - resource.Name()); - - switch (watchEventType) - { - case WatchEventType.Added: - case WatchEventType.Modified: - resource = _resourceCache.Upsert(resource, out var state); - output = MapCacheResult(state, resource); - break; - case WatchEventType.Deleted: - _resourceCache.Remove(resource); - output = new ResourceEvent(ResourceEventType.Deleted, resource); - break; - case WatchEventType.Error: - case WatchEventType.Bookmark: - default: - var ex = new ArgumentException( - "The watcher event is not processable (only added / modified / deleted allowed).", - nameof(watchEvent)); - _logger.LogCritical( - ex, - @"The watcher event ""{watchEvent}"" is not further processable for the resource ""{kind}/{name}"".", - watchEventType, - resource.Kind, - resource.Name()); - - throw ex; - } - - _logger.LogTrace( - @"Mapped watch event to ""{resourceEventType}"" for ""{kind}/{name}""", - output.Type, - output.Resource.Kind, - output.Resource.Name()); - - return output; - } - - private ResourceEvent MapCacheResult( - CacheComparisonResult state, - TEntity resource) - { - _logger.LogTrace( - @"Mapping cache result ""{cacheResult}"" for ""{kind}/{name}"".", - state, - resource.Kind, - resource.Name()); - - var eventType = (state, resource.Metadata.DeletionTimestamp) switch - { - (CacheComparisonResult.Other, { }) => ResourceEventType.Finalizing, - (CacheComparisonResult.Other, _) => ResourceEventType.Reconcile, - (CacheComparisonResult.StatusModified, _) => ResourceEventType.StatusUpdated, - (CacheComparisonResult.FinalizersModified, _) => ResourceEventType.FinalizerModified, - _ => throw new ArgumentException("The caching state is out of the processable range", nameof(state)), - }; - - return new ResourceEvent(eventType, resource); - } - -#nullable disable - private IObservable> UpdateResourceData( - ResourceEvent resourceEvent) - { - if (resourceEvent.Delay is null) - { - return Observable.Return(resourceEvent); - } - - return Observable.FromAsync( - async () => - { - ResourceEvent ret; - var resource = resourceEvent.Resource; - - _logger.LogTrace( - @"Update resource from k8s / cache for delayed requeue for ""{kind}/{name}"".", - resource.Kind, - resource.Name()); - - var newResource = await _kubernetesClient.Get( - resource.Name(), - resource.Namespace()); - - if (newResource == null) - { - _resourceCache.Remove(resource); - _logger.LogDebug( - @"Resource ""{kind}/{name}"" for enqueued event was not present anymore.", - resource.Kind, - resource.Name()); - ret = null; - } - else - { - newResource = _resourceCache.Upsert(newResource, out var state); - ret = MapCacheResult(state, newResource); - } - - var updatedEvent = ret; - - return updatedEvent; - }) - .Where(e => e is not null); - } -#nullable enable -} diff --git a/_old/src/KubeOps/Operator/Controller/IControllerInstanceBuilder.cs b/_old/src/KubeOps/Operator/Controller/IControllerInstanceBuilder.cs deleted file mode 100644 index 92c6db37..00000000 --- a/_old/src/KubeOps/Operator/Controller/IControllerInstanceBuilder.cs +++ /dev/null @@ -1,18 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Builder; - -namespace KubeOps.Operator.Controller; - -internal interface IControllerInstanceBuilder -{ - public delegate ScopedResourceController ControllerFactory( - IServiceProvider parent, - IComponentRegistrar.ControllerRegistration controllerRegistration); - - public IEnumerable BuildControllers(); - - public IEnumerable BuildControllers() - where TEntity : IKubernetesObject; -} diff --git a/_old/src/KubeOps/Operator/Controller/IEventQueue.cs b/_old/src/KubeOps/Operator/Controller/IEventQueue.cs deleted file mode 100644 index 0bccd602..00000000 --- a/_old/src/KubeOps/Operator/Controller/IEventQueue.cs +++ /dev/null @@ -1,16 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Controller; - -public interface IEventQueue - where TEntity : class, IKubernetesObject -{ - public IObservable> Events { get; } - - public Task StartAsync(Action> onWatcherEvent); - - public Task StopAsync(); - - public void EnqueueLocal(ResourceEvent resourceEvent); -} diff --git a/_old/src/KubeOps/Operator/Controller/IManagedResourceController.cs b/_old/src/KubeOps/Operator/Controller/IManagedResourceController.cs deleted file mode 100644 index 03cb09f1..00000000 --- a/_old/src/KubeOps/Operator/Controller/IManagedResourceController.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace KubeOps.Operator.Controller; - -public interface IManagedResourceController : IDisposable -{ - Task StartAsync(); - - Task StopAsync(); -} diff --git a/_old/src/KubeOps/Operator/Controller/IResourceController{TEntity}.cs b/_old/src/KubeOps/Operator/Controller/IResourceController{TEntity}.cs deleted file mode 100644 index ef997a6b..00000000 --- a/_old/src/KubeOps/Operator/Controller/IResourceController{TEntity}.cs +++ /dev/null @@ -1,48 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Controller.Results; -using KubeOps.Operator.Kubernetes; - -namespace KubeOps.Operator.Controller; - -/// -/// Generic entity controller interface. -/// This interface is primarily used for generic type help. -/// -/// The type of the kubernetes entity. -public interface IResourceController - where TEntity : IKubernetesObject -{ - /// - /// Called for events for a given entity. - /// - /// The entity that fired the reconcile event. - /// - /// A task with an optional . - /// Use the static constructors on the class - /// to create your controller function result. - /// - Task ReconcileAsync(TEntity entity) => - Task.FromResult(null); - - /// - /// Called for events for a given entity. - /// - /// The entity that fired the status-modified event. - /// - /// A task that completes, when the reconciliation is done. - /// - Task StatusModifiedAsync(TEntity entity) => - Task.CompletedTask; - - /// - /// Called for events for a given entity. - /// - /// The entity that fired the deleted event. - /// - /// A task that completes, when the reconciliation is done. - /// - Task DeletedAsync(TEntity entity) => - Task.CompletedTask; -} diff --git a/_old/src/KubeOps/Operator/Controller/ManagedResourceController{TEntity}.cs b/_old/src/KubeOps/Operator/Controller/ManagedResourceController{TEntity}.cs deleted file mode 100644 index 6773a7eb..00000000 --- a/_old/src/KubeOps/Operator/Controller/ManagedResourceController{TEntity}.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Net; -using System.Reactive; -using System.Reactive.Concurrency; -using System.Reactive.Linq; - -using k8s; -using k8s.Autorest; -using k8s.Models; - -using KubeOps.Operator.Controller.Results; -using KubeOps.Operator.DevOps; -using KubeOps.Operator.Finalizer; -using KubeOps.Operator.Kubernetes; - -using static KubeOps.Operator.Builder.IComponentRegistrar; - -namespace KubeOps.Operator.Controller; - -internal class ManagedResourceController : IManagedResourceController - where TEntity : class, IKubernetesObject -{ - private readonly ILogger> _logger; - private readonly IServiceProvider _services; - private readonly ResourceControllerMetrics _metrics; - private readonly OperatorSettings _settings; - private readonly ControllerRegistration _controllerRegistration; - private readonly IEventQueue _eventQueue; - - private IDisposable? _eventSubscription; - - public ManagedResourceController( - ILogger> logger, - IServiceProvider services, - ResourceControllerMetrics metrics, - OperatorSettings settings, - ControllerRegistration controllerRegistration, - IEventQueue eventQueue) - { - _logger = logger; - _services = services; - _metrics = metrics; - _settings = settings; - _controllerRegistration = controllerRegistration; - _eventQueue = eventQueue; - - Events = _eventQueue - .Events - .Select(HandleEvent) - .Concat(); - } - - private IObservable Events { get; } - - public virtual async Task StartAsync() - { - _logger.LogDebug(@"Managed resource controller startup for type ""{type}"".", typeof(TEntity)); - _eventSubscription = Events.Subscribe(); - - await _eventQueue.StartAsync(_ => _metrics.EventsFromWatcher.Inc()); - _metrics.Running.Set(1); - } - - public virtual async Task StopAsync() - { - _logger.LogTrace(@"Managed resource controller shutdown for type ""{type}"".", typeof(TEntity)); - - await _eventQueue.StopAsync(); - _eventSubscription?.Dispose(); - _eventSubscription = null; - } - - public void Dispose() - { - _logger.LogTrace(@"Managed resource controller disposal for type ""{type}"".", typeof(TEntity)); - _eventSubscription?.Dispose(); - _eventSubscription = null; - _metrics.Running.Set(0); - } - - protected async Task HandleResourceEvent(ResourceEvent resourceEvent) - { - (ResourceEventType eventType, TEntity resource, _, _) = resourceEvent; - - _logger.LogDebug( - @"Execute/Reconcile event ""{eventType}"" on resource ""{kind}/{name}"".", - eventType, - resource.Kind, - resource.Name()); - - var controllerType = _controllerRegistration.ControllerType; - - ResourceControllerResult? result = null; - _logger.LogTrace(@"Instantiating new DI scope for controller ""{name}"".", controllerType.Name); - using (var scope = _services.CreateScope()) - { - if (scope.ServiceProvider.GetRequiredService(controllerType) is not IResourceController - controller) - { - var ex = new InvalidCastException( - $@"The type ""{controllerType.Namespace}.{controllerType.Name}"" is not a valid IResourceController type."); - _logger.LogCritical( - @"The type ""{namespace}.{name}"" is not a valid IResourceController type.", - controllerType.Namespace, - controllerType.Name); - throw ex; - } - - try - { - switch (eventType) - { - case ResourceEventType.Reconcile: - result = await controller.ReconcileAsync(resource); - _metrics.ReconciledEvents.Inc(); - break; - case ResourceEventType.Deleted: - await controller.DeletedAsync(resource); - _metrics.DeletedEvents.Inc(); - _logger.LogInformation( - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue not possible.", - eventType, - resource.Kind, - resource.Name()); - return; - case ResourceEventType.StatusUpdated: - await controller.StatusModifiedAsync(resource); - _metrics.StatusUpdatedEvents.Inc(); - _logger.LogInformation( - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue not possible.", - eventType, - resource.Kind, - resource.Name()); - return; - } - } - catch (HttpOperationException hoe) when (hoe.Response.StatusCode == HttpStatusCode.UnprocessableEntity) - { - var status = KubernetesJson.Deserialize(hoe.Response.Content); - _logger.LogWarning(status.Message); - RequeueError(resourceEvent, hoe); - return; - } - catch (Exception e) - { - RequeueError(resourceEvent, e); - return; - } - } - - switch (result) - { - case null: - _logger.LogInformation( - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue not requested.", - eventType, - resource.Kind, - resource.Name()); - return; - case RequeueEventResult requeue: - var specificQueueTypeRequested = requeue.EventType.HasValue; - var requestedQueueType = requeue.EventType ?? - (_settings.DefaultRequeueAsSameType - ? eventType - : ResourceEventType.Reconcile); - - if (specificQueueTypeRequested) - { - _logger.LogInformation( - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue requested as type ""{requeueType}"" with delay ""{requeue}"".", - eventType, - resource.Kind, - resource.Name(), - requestedQueueType, - requeue.RequeueIn); - } - else - { - _logger.LogInformation( - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" successfully reconciled. Requeue requested with delay ""{requeue}"".", - eventType, - resource.Kind, - resource.Name(), - requeue.RequeueIn); - } - - RequeueDelayed(resourceEvent with { Type = requestedQueueType }, requeue.RequeueIn); - break; - } - } - - protected async Task HandleResourceFinalization(ResourceEvent? resourceEvent) - { - using var scope = _services.CreateScope(); - - if (resourceEvent == null) - { - return; - } - - (_, TEntity resource, _, _) = resourceEvent; - - _logger.LogDebug( - @"Finalize resource ""{kind}/{name}"".", - resource.Kind, - resource.Name()); - - try - { - await scope.ServiceProvider.GetRequiredService>() - .FinalizeAsync(resourceEvent.Resource); - } - catch (Exception e) - { - RequeueError(resourceEvent, e); - } - } - - protected void RequeueError(ResourceEvent resourceEvent, Exception ex) - { - _metrics.ErroredEvents.Inc(); - - var attempt = resourceEvent.Attempt + 1; - var delay = _settings.ErrorBackoffStrategy(attempt); - - _logger.LogError( - ex, - @"Event type ""{eventType}"" on resource ""{kind}/{name}"" threw an error. Retry attempt {retryAttempt}.", - resourceEvent.Type, - resourceEvent.Resource.Kind, - resourceEvent.Resource.Name(), - attempt); - - _eventQueue.EnqueueLocal(resourceEvent with { Attempt = attempt, Delay = delay }); - } - - protected void RequeueDelayed(ResourceEvent resourceEvent, TimeSpan delay) - { - _metrics.RequeuedEvents.Inc(); - - _eventQueue.EnqueueLocal(resourceEvent with { Delay = delay }); - } - - private IObservable HandleEvent(ResourceEvent resourceEvent) - { - return Observable.FromAsync( - async () => await (resourceEvent.Type == ResourceEventType.Finalizing - ? HandleResourceFinalization(resourceEvent) - : HandleResourceEvent(resourceEvent)), - ThreadPoolScheduler.Instance); - } -} diff --git a/_old/src/KubeOps/Operator/Controller/ResourceControllerManager.cs b/_old/src/KubeOps/Operator/Controller/ResourceControllerManager.cs deleted file mode 100644 index 87b50d8e..00000000 --- a/_old/src/KubeOps/Operator/Controller/ResourceControllerManager.cs +++ /dev/null @@ -1,64 +0,0 @@ -using KubeOps.Operator.Leadership; - -namespace KubeOps.Operator.Controller; - -internal class ResourceControllerManager : IHostedService -{ - private readonly IControllerInstanceBuilder _controllerInstanceBuilder; - private readonly ILeaderElection _leaderElection; - private readonly OperatorSettings _operatorSettings; - private readonly List _controllerList; - - private IDisposable? _leadershipSubscription; - - public ResourceControllerManager( - IControllerInstanceBuilder controllerInstanceBuilder, - ILeaderElection leaderElection, - OperatorSettings operatorSettings) - { - _controllerInstanceBuilder = controllerInstanceBuilder; - _leaderElection = leaderElection; - _operatorSettings = operatorSettings; - _controllerList = new List(); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - _controllerList.AddRange(_controllerInstanceBuilder.BuildControllers()); - - _leadershipSubscription = _leaderElection.LeadershipChange.Subscribe(LeadershipChanged); - return Task.CompletedTask; - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - _leadershipSubscription?.Dispose(); - foreach (var controller in _controllerList) - { - await controller.StopAsync(); - controller.Dispose(); - } - - _controllerList.Clear(); - } - - private async void LeadershipChanged(LeaderState state) - { - if (state == LeaderState.None) - { - return; - } - - foreach (var controller in _controllerList) - { - if (state == LeaderState.Leader || !_operatorSettings.OnlyWatchEventsWhenLeader) - { - await controller.StartAsync(); - } - else - { - await controller.StopAsync(); - } - } - } -} diff --git a/_old/src/KubeOps/Operator/Controller/ResourceEvent.cs b/_old/src/KubeOps/Operator/Controller/ResourceEvent.cs deleted file mode 100644 index ad45687a..00000000 --- a/_old/src/KubeOps/Operator/Controller/ResourceEvent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Kubernetes; - -namespace KubeOps.Operator.Controller; - -public record ResourceEvent(ResourceEventType Type, TEntity Resource, int Attempt = 0, TimeSpan? Delay = null) - where TEntity : class, IKubernetesObject; diff --git a/_old/src/KubeOps/Operator/Controller/Results/RequeueEventResult.cs b/_old/src/KubeOps/Operator/Controller/Results/RequeueEventResult.cs deleted file mode 100644 index 3f028c36..00000000 --- a/_old/src/KubeOps/Operator/Controller/Results/RequeueEventResult.cs +++ /dev/null @@ -1,16 +0,0 @@ -using KubeOps.Operator.Kubernetes; - -namespace KubeOps.Operator.Controller.Results; - -internal sealed class RequeueEventResult : ResourceControllerResult -{ - public RequeueEventResult(TimeSpan requeueIn) - : base(requeueIn) - { - } - - public RequeueEventResult(TimeSpan requeueIn, ResourceEventType eventType) - : base(requeueIn, eventType) - { - } -} diff --git a/_old/src/KubeOps/Operator/Controller/Results/ResourceControllerResult.cs b/_old/src/KubeOps/Operator/Controller/Results/ResourceControllerResult.cs deleted file mode 100644 index 9d7ab2d5..00000000 --- a/_old/src/KubeOps/Operator/Controller/Results/ResourceControllerResult.cs +++ /dev/null @@ -1,63 +0,0 @@ -using KubeOps.Operator.Kubernetes; - -namespace KubeOps.Operator.Controller.Results; - -/// -/// Result class for determining additional actions on a controller -/// reconciliation. The additional actions are determined by the effective -/// type that is returned. -/// -public abstract class ResourceControllerResult -{ - internal ResourceControllerResult(TimeSpan delay) - { - RequeueIn = delay; - } - - internal ResourceControllerResult(TimeSpan delay, ResourceEventType eventType) - { - RequeueIn = delay; - EventType = eventType; - } - - /// - /// Time that should be waited for a requeue. - /// - public TimeSpan RequeueIn { get; } - - /// - /// Type of the event to be queued. - /// - public ResourceEventType? EventType { get; } - - /// - /// Create a that requeues a resource - /// with a given delay. When the event fires (after the delay) the resource - /// cache is consulted and the new is calculated. - /// Based on this new calculation, the new event triggers the according function. - /// - /// - /// The delay. Please note, that a delay of - /// will result in an immediate trigger of the function. This can lead to infinite circles. - /// - /// The with the configured delay. - public static ResourceControllerResult RequeueEvent(TimeSpan delay) - => new RequeueEventResult(delay); - - /// - /// Create a that requeues a resource - /// with a given delay. When the event fires (after the delay) the resource - /// cache is ignored in favor the specified . - /// Based on the specified type, the new event triggers the according function. - /// - /// - /// The delay. Please note, that a delay of - /// will result in an immediate trigger of the function. This can lead to infinite circles. - /// - /// - /// The event type to queue. - /// - /// The with the configured delay and event type. - public static ResourceControllerResult RequeueEvent(TimeSpan delay, ResourceEventType eventType) - => new RequeueEventResult(delay, eventType); -} diff --git a/_old/src/KubeOps/Operator/Controller/ScopedResourceController.cs b/_old/src/KubeOps/Operator/Controller/ScopedResourceController.cs deleted file mode 100644 index 0b623e78..00000000 --- a/_old/src/KubeOps/Operator/Controller/ScopedResourceController.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace KubeOps.Operator.Controller; - -internal class ScopedResourceController : IManagedResourceController -{ - private readonly IDisposable _scope; - private readonly IManagedResourceController _controller; - - public ScopedResourceController(IDisposable scope, IManagedResourceController controller) - { - _scope = scope; - _controller = controller; - } - - public void Dispose() => _scope.Dispose(); - - public async Task StartAsync() => await _controller.StartAsync(); - - public async Task StopAsync() => await _controller.StopAsync(); -} diff --git a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity.cs b/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity.cs deleted file mode 100644 index 49bab1f7..00000000 --- a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity.cs +++ /dev/null @@ -1,15 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Entities; - -/// -/// Defines a custom kubernetes entity which can be used in finalizers and controllers. -/// -public abstract class CustomKubernetesEntity : KubernetesObject, IKubernetesObject -{ - /// - /// The metadata of the kubernetes object. - /// - public V1ObjectMeta Metadata { get; set; } = new(); -} diff --git a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec,TStatus}.cs b/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec,TStatus}.cs deleted file mode 100644 index 91fe99d3..00000000 --- a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec,TStatus}.cs +++ /dev/null @@ -1,21 +0,0 @@ -using k8s; - -namespace KubeOps.Operator.Entities; - -/// -/// Defines a custom kubernetes entity which can be used in finalizers and controllers. -/// This entity contains a spec (like ) -/// and a status () which can be updated to reflect the state -/// of the entity. -/// -/// The type of the specified data. -/// The type of the status data. -public abstract class CustomKubernetesEntity : CustomKubernetesEntity, IStatus - where TSpec : new() - where TStatus : new() -{ - /// - /// Status object for the entity. - /// - public TStatus Status { get; set; } = new(); -} diff --git a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec}.cs b/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec}.cs deleted file mode 100644 index 6eeeaa48..00000000 --- a/_old/src/KubeOps/Operator/Entities/CustomKubernetesEntity{TSpec}.cs +++ /dev/null @@ -1,17 +0,0 @@ -using k8s; - -namespace KubeOps.Operator.Entities; - -/// -/// Defines a custom kubernetes entity which can be used in finalizers and controllers. -/// This entity contains a , which means in contains specified data. -/// -/// The type of the specified data. -public abstract class CustomKubernetesEntity : CustomKubernetesEntity, ISpec - where TSpec : new() -{ - /// - /// Specification of the kubernetes object. - /// - public TSpec Spec { get; set; } = new(); -} diff --git a/_old/src/KubeOps/Operator/Entities/EntityList.cs b/_old/src/KubeOps/Operator/Entities/EntityList.cs deleted file mode 100644 index 77afef34..00000000 --- a/_old/src/KubeOps/Operator/Entities/EntityList.cs +++ /dev/null @@ -1,22 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Entities; - -/// -/// Type for a list of entities. -/// -/// Type for the list entries. -public class EntityList : KubernetesObject - where T : IKubernetesObject -{ - /// - /// Official list metadata object of kubernetes. - /// - public V1ListMeta Metadata { get; set; } = new(); - - /// - /// The list of items. - /// - public IList Items { get; set; } = new List(); -} diff --git a/_old/src/KubeOps/Operator/Finalizer/FinalizerInstanceBuilder.cs b/_old/src/KubeOps/Operator/Finalizer/FinalizerInstanceBuilder.cs deleted file mode 100644 index 47929f37..00000000 --- a/_old/src/KubeOps/Operator/Finalizer/FinalizerInstanceBuilder.cs +++ /dev/null @@ -1,32 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Builder; - -namespace KubeOps.Operator.Finalizer; - -internal class FinalizerInstanceBuilder : IFinalizerInstanceBuilder -{ - private readonly IComponentRegistrar _componentRegistrar; - private readonly IServiceProvider _services; - - public FinalizerInstanceBuilder( - IComponentRegistrar componentRegistrar, - IServiceProvider services) - { - _componentRegistrar = componentRegistrar; - _services = services; - } - - public IResourceFinalizer BuildFinalizer() - where TEntity : IKubernetesObject => - _componentRegistrar.FinalizerRegistrations.For() - .Where(r => r.FinalizerType.IsEquivalentTo(typeof(TFinalizer))) - .Select(r => (IResourceFinalizer)_services.GetRequiredService(r.FinalizerType)) - .Single(); - - public IEnumerable> BuildFinalizers() - where TEntity : IKubernetesObject => - _componentRegistrar.FinalizerRegistrations.For() - .Select(r => (IResourceFinalizer)_services.GetRequiredService(r.FinalizerType)); -} diff --git a/_old/src/KubeOps/Operator/Finalizer/FinalizerManager{TEntity}.cs b/_old/src/KubeOps/Operator/Finalizer/FinalizerManager{TEntity}.cs deleted file mode 100644 index 028bb8a3..00000000 --- a/_old/src/KubeOps/Operator/Finalizer/FinalizerManager{TEntity}.cs +++ /dev/null @@ -1,124 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.KubernetesClient; - -namespace KubeOps.Operator.Finalizer; - -internal class FinalizerManager : IFinalizerManager - where TEntity : IKubernetesObject -{ - private readonly IFinalizerInstanceBuilder _finalizerInstanceBuilder; - private readonly IKubernetesClient _client; - private readonly ILogger> _logger; - - public FinalizerManager( - IKubernetesClient client, - ILogger> logger, - IFinalizerInstanceBuilder finalizerInstanceBuilder) - { - _client = client; - _logger = logger; - _finalizerInstanceBuilder = finalizerInstanceBuilder; - } - - public Task RegisterFinalizerAsync(TEntity entity) - where TFinalizer : IResourceFinalizer - => RegisterFinalizerInternalAsync(entity, _finalizerInstanceBuilder.BuildFinalizer()); - - public async Task RegisterAllFinalizersAsync(TEntity entity) - { - await Task.WhenAll( - _finalizerInstanceBuilder.BuildFinalizers() - .Select(f => RegisterFinalizerInternalAsync(entity, f))); - } - - public async Task RemoveFinalizerAsync(TEntity entity) - where TFinalizer : IResourceFinalizer - { - var finalizer = _finalizerInstanceBuilder.BuildFinalizer(); - - _logger.LogTrace( - @"Try to add finalizer ""{finalizer}"" on entity ""{kind}/{name}"".", - finalizer.Identifier, - entity.Kind, - entity.Name()); - - if (entity.RemoveFinalizer(finalizer.Identifier)) - { - _logger.LogInformation( - @"Removed finalizer ""{finalizer}"" on entity ""{kind}/{name}"".", - finalizer.Identifier, - entity.Kind, - entity.Name()); - await _client.Update(entity); - } - } - - async Task IFinalizerManager.FinalizeAsync(TEntity entity) - { - var semaphore = new SemaphoreSlim(1); - - _logger.LogTrace( - @"Try to finalize entity ""{kind}/{name}"".", - entity.Kind, - entity.Name()); - - var finalizerCalled = false; - await Task.WhenAll( - _finalizerInstanceBuilder.BuildFinalizers() - .Where(finalizer => entity.HasFinalizer(finalizer.Identifier)) - .Select( - finalizer => Task.Run( - async () => - { - finalizerCalled = true; - _logger.LogInformation( - @"Execute finalizer ""{finalizer}"" on entity ""{kind}/{name}"".", - finalizer.Identifier, - entity.Kind, - entity.Name()); - try - { - await semaphore.WaitAsync(); - await finalizer.FinalizeAsync(entity); - entity.RemoveFinalizer(finalizer.Identifier); - } - finally - { - semaphore.Release(); - } - }))); - - if (finalizerCalled) - { - await _client.Update(entity); - } - - _logger.LogDebug( - @"Finalization on entity ""{kind}/{name}"" done. Remaining finalizers: ""{remainingFinalizer}"".", - entity.Kind, - entity.Name(), - string.Join(',', entity.Finalizers() ?? Array.Empty())); - } - - private async Task RegisterFinalizerInternalAsync(TEntity entity, TFinalizer finalizer) - where TFinalizer : IResourceFinalizer - { - _logger.LogTrace( - @"Try to add finalizer ""{finalizer}"" on entity ""{kind}/{name}"".", - finalizer.Identifier, - entity.Kind, - entity.Name()); - - if (entity.AddFinalizer(finalizer.Identifier)) - { - _logger.LogInformation( - @"Added finalizer ""{finalizer}"" on entity ""{kind}/{name}"".", - finalizer.Identifier, - entity.Kind, - entity.Name()); - await _client.Update(entity); - } - } -} diff --git a/_old/src/KubeOps/Operator/Finalizer/IFinalizerInstanceBuilder.cs b/_old/src/KubeOps/Operator/Finalizer/IFinalizerInstanceBuilder.cs deleted file mode 100644 index 4a511ca1..00000000 --- a/_old/src/KubeOps/Operator/Finalizer/IFinalizerInstanceBuilder.cs +++ /dev/null @@ -1,13 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Finalizer; - -internal interface IFinalizerInstanceBuilder -{ - public IEnumerable> BuildFinalizers() - where TEntity : IKubernetesObject; - - IResourceFinalizer BuildFinalizer() - where TEntity : IKubernetesObject; -} diff --git a/_old/src/KubeOps/Operator/Finalizer/IFinalizerManager{TEntity}.cs b/_old/src/KubeOps/Operator/Finalizer/IFinalizerManager{TEntity}.cs deleted file mode 100644 index 24aec53b..00000000 --- a/_old/src/KubeOps/Operator/Finalizer/IFinalizerManager{TEntity}.cs +++ /dev/null @@ -1,40 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Finalizer; - -/// -/// Finalizer manager to attach finalizer to resources. -/// -/// The type of the kubernetes entity. -public interface IFinalizerManager - where TEntity : IKubernetesObject -{ - /// - /// Register a for the entity type on the provided instance. - /// - /// The entity that will receive the finalizer. - /// The type of the finalizer. - /// A task when the operation is done. - Task RegisterFinalizerAsync(TEntity entity) - where TFinalizer : IResourceFinalizer; - - /// - /// Register all known for the entity type on the provided instance. - /// - /// The entity that will receive the finalizers. - /// A task when the operation is done. - Task RegisterAllFinalizersAsync(TEntity entity); - - /// - /// Remove a given from an entity, if - /// it is registered. - /// - /// The entity that should have the finalizer removed. - /// The type of the finalizer. - /// A task when the operation is done. - Task RemoveFinalizerAsync(TEntity entity) - where TFinalizer : IResourceFinalizer; - - internal Task FinalizeAsync(TEntity entity); -} diff --git a/_old/src/KubeOps/Operator/Finalizer/IResourceFinalizer.cs b/_old/src/KubeOps/Operator/Finalizer/IResourceFinalizer.cs deleted file mode 100644 index f3a2d644..00000000 --- a/_old/src/KubeOps/Operator/Finalizer/IResourceFinalizer.cs +++ /dev/null @@ -1,42 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.KubernetesClient.Entities; - -namespace KubeOps.Operator.Finalizer; - -/// -/// Finalizer for a resource. -/// -/// The type of the resources (entities). -public interface IResourceFinalizer - where TEntity : IKubernetesObject -{ - private const byte MaxNameLength = 63; - - /// - /// Unique identifier for this finalizer. - /// Defaults to `"{Typename}.{crd.Singular}.finalizers.{crd.Group}"`. - /// - /// testentityfinalizer.test.finalizer.dev. - string Identifier - { - get - { - var crd = EntityDefinition.FromType(); - var finalizerName = GetType().Name.ToLowerInvariant(); - var name = - $"{crd.Group}/{GetType().Name.ToLowerInvariant()}{(finalizerName.EndsWith("finalizer") ? string.Empty : "finalizer")}"; - return name.Length > MaxNameLength - ? name[..MaxNameLength] - : name; - } - } - - /// - /// Finalize a resource that is pending for deletion. - /// - /// The kubernetes entity that needs to be finalized. - /// A task for when the operation is done. - Task FinalizeAsync(TEntity entity); -} diff --git a/_old/src/KubeOps/Operator/HashSetExtensions.cs b/_old/src/KubeOps/Operator/HashSetExtensions.cs deleted file mode 100644 index 9eb4cb79..00000000 --- a/_old/src/KubeOps/Operator/HashSetExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Immutable; - -using static KubeOps.Operator.Builder.IComponentRegistrar; - -namespace KubeOps.Operator; - -internal static class HashSetExtensions -{ - public static IEnumerable For( - this ImmutableHashSet registrations) - => registrations.Where(r => r.EntityType.IsEquivalentTo(typeof(TEntity))); - - public static IEnumerable For( - this ImmutableHashSet registrations) - => registrations.Where(r => r.EntityType.IsEquivalentTo(typeof(TEntity))); - - public static IEnumerable For( - this ImmutableHashSet registrations) - => registrations.Where(r => r.EntityType.IsEquivalentTo(typeof(TEntity))); - - public static IEnumerable For( - this ImmutableHashSet registrations) - => registrations.Where(r => r.EntityType.IsEquivalentTo(typeof(TEntity))); -} diff --git a/_old/src/KubeOps/Operator/HostExtensions.cs b/_old/src/KubeOps/Operator/HostExtensions.cs deleted file mode 100644 index 558077d8..00000000 --- a/_old/src/KubeOps/Operator/HostExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using KubeOps.Operator.Commands; - -using McMaster.Extensions.CommandLineUtils; - -namespace KubeOps.Operator; - -/// -/// Extensions for the . -/// -public static class HostExtensions -{ - /// - /// Run the operator with default settings. - /// Creates the application, creates the constructor-injection - /// and runs the application with the given arguments. - /// - /// The . - /// Program arguments. - /// Async task with completion result. - public static async Task RunOperatorAsync(this IHost host, string[] args) - { - var app = new CommandLineApplication(); - app - .Conventions - .UseDefaultConventions() - .UseConstructorInjection(host.Services); - try - { - return await app.ExecuteAsync(args); - } - catch (UnrecognizedCommandParsingException ex) - { - Console.WriteLine(ex.Message); - ex.Command.Description = null; - ex.Command.ShowHelp(); - return 1; - } - } -} diff --git a/_old/src/KubeOps/Operator/Kubernetes/IResourceWatcher.cs b/_old/src/KubeOps/Operator/Kubernetes/IResourceWatcher.cs deleted file mode 100644 index 9dc22dbf..00000000 --- a/_old/src/KubeOps/Operator/Kubernetes/IResourceWatcher.cs +++ /dev/null @@ -1,14 +0,0 @@ -using k8s; -using k8s.Models; - -namespace KubeOps.Operator.Kubernetes; - -internal interface IResourceWatcher - where TEntity : IKubernetesObject -{ - IObservable.WatchEvent> WatchEvents { get; } - - Task StartAsync(); - - Task StopAsync(); -} diff --git a/_old/src/KubeOps/Operator/Kubernetes/ResourceEventType.cs b/_old/src/KubeOps/Operator/Kubernetes/ResourceEventType.cs deleted file mode 100644 index 8d8689db..00000000 --- a/_old/src/KubeOps/Operator/Kubernetes/ResourceEventType.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace KubeOps.Operator.Kubernetes; - -/// -/// Event type for resources. -/// -public enum ResourceEventType -{ - /// - /// Fired when a resource (even requeued) is catched by the watcher and needs to be reconciled. - /// - Reconcile, - - /// - /// Fired when a resource was removed from the system. - /// - Deleted, - - /// - /// Fired when the status part of a resource changed but nothing else. - /// - StatusUpdated, - - /// - /// Fired when the resource is marked for deletion but has pending finalizers. - /// - Finalizing, - - /// - /// Fired when the resource has it's finalizers modified. - /// - FinalizerModified, -} diff --git a/_old/src/KubeOps/Operator/Kubernetes/ResourceWatcher{TEntity}.cs b/_old/src/KubeOps/Operator/Kubernetes/ResourceWatcher{TEntity}.cs deleted file mode 100644 index d34ea15d..00000000 --- a/_old/src/KubeOps/Operator/Kubernetes/ResourceWatcher{TEntity}.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System.Reactive.Concurrency; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Runtime.Serialization; -using System.Text.Json; - -using k8s; -using k8s.Models; - -using KubeOps.KubernetesClient; -using KubeOps.Operator.DevOps; - -namespace KubeOps.Operator.Kubernetes; - -internal class ResourceWatcher : IDisposable, IResourceWatcher - where TEntity : IKubernetesObject -{ - private const int MaxRetriesAttempts = 39; - - private readonly Subject _watchEvents = new(); - private readonly IKubernetesClient _client; - private readonly ILogger> _logger; - private readonly IResourceWatcherMetrics _metrics; - private readonly OperatorSettings _settings; - private readonly Subject _reconnectHandler = new(); - private readonly IDisposable _reconnectSubscription; - - private IDisposable? _resetReconnectCounter; - private int _reconnectAttempts; - private CancellationTokenSource? _cancellation; - private Watcher? _watcher; - - public ResourceWatcher( - IKubernetesClient client, - ILogger> logger, - IResourceWatcherMetrics metrics, - OperatorSettings settings) - { - _client = client; - _logger = logger; - _metrics = metrics; - _settings = settings; - _reconnectSubscription = - _reconnectHandler - .Select(backoff => Observable.Timer(backoff, TimeBasedScheduler)) - .Switch() - .Retry() - .Subscribe(async _ => await WatchResource(), error => _logger.LogError(error, $"There was an error while restarting the resource watcher {typeof(TEntity)}")); - } - - public IObservable WatchEvents => _watchEvents; - - internal IScheduler TimeBasedScheduler { get; set; } = DefaultScheduler.Instance; - - private TimeSpan DefaultBackoff => _settings.ErrorBackoffStrategy(1); - - public Task StartAsync() - { - _logger.LogDebug(@"Resource Watcher startup for type ""{type}"".", typeof(TEntity)); - return WatchResource(); - } - - public Task StopAsync() - { - _logger.LogTrace(@"Resource Watcher shutdown for type ""{type}"".", typeof(TEntity)); - Disposing(true); - return Task.CompletedTask; - } - - public void Dispose() - { - Disposing(false); - } - - private void Disposing(bool fromStop) - { - if (!fromStop) - { - _watchEvents.Dispose(); - _reconnectHandler.Dispose(); - _reconnectSubscription.Dispose(); - } - - _resetReconnectCounter?.Dispose(); - - if (_cancellation?.IsCancellationRequested == false) - { - _cancellation.Cancel(); - } - - _cancellation?.Dispose(); - _watcher?.Dispose(); - _logger.LogTrace(@"Disposed resource watcher for type ""{type}"".", typeof(TEntity)); - _metrics.Running.Set(0); - } - - private async Task WatchResource() - { - if (_watcher != null) - { - if (!_watcher.Watching) - { - _watcher.Dispose(); - } - else - { - _logger.LogTrace(@"Watcher for type ""{type}"" already running.", typeof(TEntity)); - return; - } - } - - _cancellation = new CancellationTokenSource(); - - _watcher = await _client.Watch( - TimeSpan.FromSeconds(_settings.WatcherHttpTimeout), - OnWatcherEvent, - OnException, - OnClose, - _settings.Namespace, - _cancellation.Token); - _metrics.Running.Set(1); - } - - private void OnWatcherEvent(WatchEventType type, TEntity resource) - { - _logger.LogTrace( - @"Received watch event ""{eventType}"" for ""{kind}/{name}"".", - type, - resource.Kind, - resource.Metadata.Name); - - _metrics.WatchedEvents.Inc(); - - switch (type) - { - case WatchEventType.Added: - case WatchEventType.Modified: - case WatchEventType.Deleted: - _watchEvents.OnNext(new WatchEvent(type, resource)); - break; - - case WatchEventType.Error: - case WatchEventType.Bookmark: - break; - - default: - throw new ArgumentOutOfRangeException(nameof(type), type, "Event did not match."); - } - } - - private async void RestartWatcher() - { - _logger.LogTrace(@"Restarting resource watcher for type ""{type}"".", typeof(TEntity)); - _cancellation?.Cancel(); - _watcher?.Dispose(); - _watcher = null; - await WatchResource(); - } - - private void OnException(Exception e) - { - switch (e) - { - case SerializationException when - e.InnerException is JsonException && - e.InnerException.Message.Contains("The input does not contain any JSON tokens"): - _logger.LogDebug( - @"The watcher received an empty response for resource ""{resource}"".", - typeof(TEntity)); - return; - - // this is a workaround for a bug in the kubernetes client. https://github.com/kubernetes-client/csharp/issues/893 - case HttpRequestException hre when - e.InnerException is EndOfStreamException && - e.InnerException.Message.Contains("Attempted to read past the end of the stream."): - _logger.LogDebug( - @"The watcher received a known error from the watched resource ""{resource}"". This indicates that there are no instances of this resource.", - typeof(TEntity)); - return; - } - - var backoff = DefaultBackoff; - - try - { - _cancellation?.Cancel(); - _watcher?.Dispose(); - _watcher = null; - - _metrics.Running.Set(0); - _metrics.WatcherExceptions.Inc(); - - switch (e) - { - case TaskCanceledException when e.InnerException is IOException: - _logger.LogTrace( - @"Either the server or the client did close the connection on watcher for resource ""{resource}"". Restart.", - typeof(TEntity)); - WatchResource().ConfigureAwait(false); - return; - } - - ++_reconnectAttempts; - - _logger.LogError(e, @"There was an error while watching the resource ""{resource}"".", typeof(TEntity)); - backoff = _settings.ErrorBackoffStrategy( - _reconnectAttempts > MaxRetriesAttempts ? MaxRetriesAttempts : _reconnectAttempts); - if (backoff.TotalSeconds > _settings.WatcherMaxRetrySeconds) - { - backoff = TimeSpan.FromSeconds(_settings.WatcherMaxRetrySeconds); - } - - _logger.LogInformation("Trying to reconnect with exponential backoff {backoff}.", backoff); - _resetReconnectCounter?.Dispose(); - _resetReconnectCounter = Observable - .Timer(TimeSpan.FromMinutes(1)) - .FirstAsync() - .Subscribe(_ => _reconnectAttempts = 0); - } - catch (Exception exception) - { - _logger.LogError(exception, @"There was an error in OnException handler ""{resource}"".", typeof(TEntity)); - } - finally - { - _reconnectHandler.OnNext(backoff); - } - } - - private void OnClose() - { - _metrics.Running.Set(0); - _metrics.WatcherClosed.Inc(); - - if (_cancellation?.IsCancellationRequested == false) - { - _logger.LogDebug("The server closed the connection. Trying to reconnect."); - RestartWatcher(); - } - } - - internal record WatchEvent(WatchEventType Type, TEntity Resource); -} diff --git a/_old/src/KubeOps/Operator/OperatorBuilderExtensions.cs b/_old/src/KubeOps/Operator/OperatorBuilderExtensions.cs deleted file mode 100644 index 218afcf1..00000000 --- a/_old/src/KubeOps/Operator/OperatorBuilderExtensions.cs +++ /dev/null @@ -1,167 +0,0 @@ -using k8s; -using k8s.Models; - -using KubeOps.Operator.Builder; -using KubeOps.Operator.Controller; -using KubeOps.Operator.Finalizer; -using KubeOps.Operator.Webhooks; - -namespace KubeOps.Operator; - -public static class OperatorBuilderExtensions -{ - /// - /// - /// Adds an controller to the operator and registers it to be used for all entities supported - /// by its type definition. - /// - /// - /// Only useful if the assembly containing the given type is not already automatically scanned. - /// - /// - /// The builder (provided via extension instead of direct call). - /// The type of the controller to register. - /// The builder for chaining. - public static IOperatorBuilder AddController(this IOperatorBuilder builder) - where TImplementation : class - { - var entityTypes = typeof(TImplementation).GetInterfaces() - .Where( - t => - t.IsConstructedGenericType && - t.GetGenericTypeDefinition().IsEquivalentTo(typeof(IResourceController<>))) - .Select(i => i.GenericTypeArguments[0]); - - var genericRegistrationMethod = builder - .GetType() - .GetMethods() - .Single(m => m.Name == nameof(AddController) && m.GetGenericArguments().Length == 2); - - foreach (var entityType in entityTypes) - { - var registrationMethod = - genericRegistrationMethod.MakeGenericMethod(typeof(TImplementation), entityType); - registrationMethod.Invoke(builder, Array.Empty()); - } - - return builder; - } - - /// - /// - /// Adds a finalizer to the operator and registers it to be used for all entities supported - /// by its type definition. - /// - /// - /// Only useful if the assembly containing the given type is not already automatically scanned. - /// - /// - /// The builder (provided via extension instead of direct call). - /// The type of the finalizer to register. - /// The builder for chaining. - public static IOperatorBuilder AddFinalizer(this IOperatorBuilder builder) - where TImplementation : class - { - var entityTypes = typeof(TImplementation).GetInterfaces() - .Where( - t => - t.IsConstructedGenericType && - t.GetGenericTypeDefinition().IsEquivalentTo(typeof(IResourceFinalizer<>))) - .Select(i => i.GenericTypeArguments[0]); - - var genericRegistrationMethod = builder - .GetType() - .GetMethods() - .Single(m => m.Name == nameof(AddFinalizer) && m.GetGenericArguments().Length == 2); - - foreach (var entityType in entityTypes) - { - var registrationMethod = - genericRegistrationMethod.MakeGenericMethod(typeof(TImplementation), entityType); - registrationMethod.Invoke(builder, Array.Empty()); - } - - return builder; - } - - /// - /// - /// Adds a validating webhook to the operator and registers it to be used for all entities - /// supported by its type definition. - /// - /// - /// Only useful if the assembly containing the given type is not already automatically scanned. - /// - /// - /// The builder (provided via extension instead of direct call). - /// The type of the webhook to register. - /// The builder for chaining. - public static IOperatorBuilder AddValidationWebhook(this IOperatorBuilder builder) - where TImplementation : class - { - var entityTypes = typeof(TImplementation).GetInterfaces() - .Where( - t => - t.IsConstructedGenericType && - t.GetGenericTypeDefinition().IsEquivalentTo(typeof(IValidationWebhook<>))) - .Select(i => i.GenericTypeArguments[0]); - - var genericRegistrationMethod = builder - .GetType() - .GetMethods() - .Single(m => m.Name == nameof(AddValidationWebhook) && m.GetGenericArguments().Length == 2); - - foreach (var entityType in entityTypes) - { - var registrationMethod = - genericRegistrationMethod.MakeGenericMethod(typeof(TImplementation), entityType); - registrationMethod.Invoke(builder, Array.Empty()); - } - - return builder; - } - - /// - /// - /// Adds a mutating webhook to the operator and registers it to be used for all entities - /// supported by its type definition. - /// - /// - /// Only useful if the assembly containing the given type is not already automatically scanned. - /// - /// - /// The builder (provided via extension instead of direct call). - /// The type of the webhook to register. - /// The builder for chaining. - public static IOperatorBuilder AddMutationWebhook(this IOperatorBuilder builder) - where TImplementation : class - { - var entityTypes = typeof(TImplementation).GetInterfaces() - .Where( - t => - t.IsConstructedGenericType && - t.GetGenericTypeDefinition().IsEquivalentTo(typeof(IMutationWebhook<>))) - .Select(i => i.GenericTypeArguments[0]); - - var genericRegistrationMethod = builder - .GetType() - .GetMethods() - .Single(m => m.Name == nameof(AddMutationWebhook) && m.GetGenericArguments().Length == 2); - - foreach (var entityType in entityTypes) - { - var registrationMethod = - genericRegistrationMethod.MakeGenericMethod(typeof(TImplementation), entityType); - registrationMethod.Invoke(builder, Array.Empty()); - } - - return builder; - } - - // Yes, this is here for a reason. To avoid complexity in AssemblyScanner, - // this class needed to have a method for AddEntity, even though it is a - // private method that is a straight pass-through to the interface's method. - internal static IOperatorBuilder AddEntity(this IOperatorBuilder builder) - where TEntity : IKubernetesObject - => builder.AddEntity(); -} diff --git a/_old/src/KubeOps/Operator/Rbac/EntityRbacAttribute.cs b/_old/src/KubeOps/Operator/Rbac/EntityRbacAttribute.cs deleted file mode 100644 index c6a3e2e7..00000000 --- a/_old/src/KubeOps/Operator/Rbac/EntityRbacAttribute.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace KubeOps.Operator.Rbac; - -/// -/// Generate rbac information for a type. -/// Attach this attribute to a controller with the type reference to -/// a custom entity to define rbac needs for this given type(s). -/// -/// [EntityRbac(typeof(V1TestEntity), Verbs = RbacVerb.All)]. -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class EntityRbacAttribute : Attribute -{ - public EntityRbacAttribute(params Type[] entities) - { - Entities = entities; - } - - /// - /// List of types that this rbac verbs are valid. - /// - public IEnumerable Entities { get; } - - /// - /// Flags ("list") of allowed verbs. - /// - /// Yaml example: - /// "verbs: ["get", "list", "watch"]". - /// - public RbacVerb Verbs { get; init; } -} diff --git a/_old/src/KubeOps/Operator/Rbac/GenericRbacAttribute.cs b/_old/src/KubeOps/Operator/Rbac/GenericRbacAttribute.cs deleted file mode 100644 index 5ecc1afb..00000000 --- a/_old/src/KubeOps/Operator/Rbac/GenericRbacAttribute.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace KubeOps.Operator.Rbac; - -/// -/// Generic attribute to define rbac needs for the operator. -/// This needs get generated into rbac - yaml style resources -/// for installation on a cluster. -/// -/// The attribute essentially defines the role definition of kubernetes. -/// -[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class GenericRbacAttribute : Attribute -{ - /// - /// List of groups. - /// - /// Yaml example: - /// "apiGroups: ...". - /// - public string[] Groups { get; init; } = { }; - - /// - /// List of resources. - /// - /// Yaml example: - /// "resources: ["pods"]". - /// - public string[] Resources { get; init; } = { }; - - /// - /// List of urls. - /// - public string[] Urls { get; init; } = { }; - - /// - /// Flags ("list") of allowed verbs. - /// - /// Yaml example: - /// "verbs: ["get", "list", "watch"]". - /// - public RbacVerb Verbs { get; init; } -} diff --git a/_old/src/KubeOps/Operator/Rbac/IRbacBuilder.cs b/_old/src/KubeOps/Operator/Rbac/IRbacBuilder.cs deleted file mode 100644 index ebc12890..00000000 --- a/_old/src/KubeOps/Operator/Rbac/IRbacBuilder.cs +++ /dev/null @@ -1,8 +0,0 @@ -using k8s.Models; - -namespace KubeOps.Operator.Rbac; - -internal interface IRbacBuilder -{ - V1ClusterRole BuildManagerRbac(); -} diff --git a/_old/src/KubeOps/Operator/Rbac/RbacAttributeExtensions.cs b/_old/src/KubeOps/Operator/Rbac/RbacAttributeExtensions.cs deleted file mode 100644 index d9f195b1..00000000 --- a/_old/src/KubeOps/Operator/Rbac/RbacAttributeExtensions.cs +++ /dev/null @@ -1,111 +0,0 @@ -using k8s.Models; - -using KubeOps.KubernetesClient.Entities; - -namespace KubeOps.Operator.Rbac; - -internal static class RbacAttributeExtensions -{ - public static IEnumerable CreateRbacPolicies(this IEnumerable attributes) - { - var attributeList = attributes.ToList(); - - return attributeList.CreateEntityPolicies().Concat(attributeList.CreateEntityStatusPolicies()); - } - - public static V1PolicyRule CreateRbacPolicy(this GenericRbacAttribute attribute) => new() - { - ApiGroups = attribute.Groups, - Resources = attribute.Resources, - NonResourceURLs = attribute.Urls, - Verbs = attribute.Verbs.ConvertToStrings(), - }; - - private static IEnumerable CreateEntityPolicies(this IEnumerable attributes) - => attributes - .SelectMany(attribute => attribute.Entities.Select(type => (EntityType: type, attribute.Verbs))) - .GroupBy(e => e.EntityType) - .Select( - group => ( - Crd: group.Key.ToEntityDefinition(), - Verbs: group.Aggregate(RbacVerb.None, (accumulator, element) => accumulator | element.Verbs))) - .GroupBy(group => group.Verbs) - .Select( - group => ( - Verbs: group.Key, - Crds: group.Select(element => element.Crd).ToList())) - .Select( - group => new V1PolicyRule - { - ApiGroups = group.Crds.Select(crd => crd.Group).Distinct().ToList(), - Resources = group.Crds.Select(crd => crd.Plural).Distinct().ToList(), - Verbs = group.Verbs.ConvertToStrings(), - }); - - private static IEnumerable CreateEntityStatusPolicies( - this IEnumerable attributes) - => attributes - .SelectMany(attribute => attribute.Entities.Select(type => (EntityType: type, attribute.Verbs))) - .Where(e => e.EntityType.GetProperty("Status") != null) - .GroupBy(e => e.EntityType) - .Select(group => group.Key.ToEntityDefinition()) - .Select( - crd => new V1PolicyRule() - { - ApiGroups = new[] { crd.Group }, - Resources = new[] { $"{crd.Plural}/status" }, - Verbs = (RbacVerb.Get | RbacVerb.Patch | RbacVerb.Update).ConvertToStrings(), - }); - - private static IList ConvertToStrings(this RbacVerb verbs) - { - if (verbs == RbacVerb.None) - { - return new List(); - } - - if (verbs.HasFlag(RbacVerb.All)) - { - return new List { "*" }; - } - - var result = new List(); - - if (verbs.HasFlag(RbacVerb.Create)) - { - result.Add("create"); - } - - if (verbs.HasFlag(RbacVerb.Get)) - { - result.Add("get"); - } - - if (verbs.HasFlag(RbacVerb.List)) - { - result.Add("list"); - } - - if (verbs.HasFlag(RbacVerb.Watch)) - { - result.Add("watch"); - } - - if (verbs.HasFlag(RbacVerb.Patch)) - { - result.Add("patch"); - } - - if (verbs.HasFlag(RbacVerb.Update)) - { - result.Add("update"); - } - - if (verbs.HasFlag(RbacVerb.Delete)) - { - result.Add("delete"); - } - - return result; - } -} diff --git a/_old/src/KubeOps/Operator/Rbac/RbacBuilder.cs b/_old/src/KubeOps/Operator/Rbac/RbacBuilder.cs deleted file mode 100644 index f68c07e4..00000000 --- a/_old/src/KubeOps/Operator/Rbac/RbacBuilder.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Reflection; - -using k8s.Models; - -using KubeOps.Operator.Builder; - -namespace KubeOps.Operator.Rbac; - -internal class RbacBuilder : IRbacBuilder -{ - private readonly List _componentTypes; - - private readonly bool _hasWebhooks; - private readonly bool _hasLeaderElection; - - public RbacBuilder(IComponentRegistrar componentRegistrar, OperatorSettings settings) - { - var controllerTypes = componentRegistrar.ControllerRegistrations - .Select(t => t.ControllerType) - .ToList(); - var finalizerTypes = componentRegistrar.FinalizerRegistrations - .Select(t => t.FinalizerType) - .ToList(); - var validatorTypes = componentRegistrar.ValidatorRegistrations - .Select(t => t.ValidatorType) - .ToList(); - var mutatorTypes = componentRegistrar.MutatorRegistrations - .Select(t => t.MutatorType) - .ToList(); - var entityTypes = componentRegistrar.EntityRegistrations - .Select(t => t.EntityType) - .ToList(); - - _componentTypes = Enumerable.Empty() - .Concat(controllerTypes) - .Concat(finalizerTypes) - .Concat(validatorTypes) - .Concat(mutatorTypes) - .Concat(entityTypes) - .Distinct() - .ToList(); - - _hasWebhooks = validatorTypes.Any() || mutatorTypes.Any(); - _hasLeaderElection = settings.EnableLeaderElection; - } - - public V1ClusterRole BuildManagerRbac() - { - var entityAttributes = GetAttributes() - .Concat( - new[] - { - new EntityRbacAttribute(typeof(Corev1Event)) - { - Verbs = RbacVerb.Get | RbacVerb.List | RbacVerb.Create | RbacVerb.Update, - }, - }); - - if (_hasWebhooks) - { - entityAttributes = entityAttributes.Concat( - new[] - { - new EntityRbacAttribute( - typeof(V1Service), - typeof(V1ValidatingWebhookConfiguration), - typeof(V1MutatingWebhookConfiguration)) - { - Verbs = RbacVerb.Get | RbacVerb.Create | RbacVerb.Update | RbacVerb.Patch | RbacVerb.Delete, - }, - }); - } - - if (_hasLeaderElection) - { - entityAttributes = entityAttributes.Concat( - new[] - { - new EntityRbacAttribute(typeof(V1Lease)) { Verbs = RbacVerb.All }, - new EntityRbacAttribute(typeof(V1Deployment)) { Verbs = RbacVerb.Get | RbacVerb.List }, - }); - } - - var genericRbacPolicyRules = GetAttributes() - .Select(attribute => attribute.CreateRbacPolicy()); - - var rules = entityAttributes - .CreateRbacPolicies() - .Concat(genericRbacPolicyRules) - .ToList(); - - return new( - null, - $"{V1ClusterRole.KubeGroup}/{V1ClusterRole.KubeApiVersion}", - V1ClusterRole.KubeKind, - new() { Name = "operator-role" }, - new List(rules)); - } - - private IEnumerable GetAttributes() - where TAttribute : Attribute => - _componentTypes.SelectMany(type => type.GetCustomAttributes(true)); -} diff --git a/_old/src/KubeOps/Operator/Rbac/RbacVerbs.cs b/_old/src/KubeOps/Operator/Rbac/RbacVerbs.cs deleted file mode 100644 index 8a28efec..00000000 --- a/_old/src/KubeOps/Operator/Rbac/RbacVerbs.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace KubeOps.Operator.Rbac; - -/// -/// List of possible rbac verbs. -/// -[Flags] -public enum RbacVerb -{ - /// - /// No permissions on the resource. - /// - None = 0, - - /// - /// All possible permissions. - /// - All = 1 << 0, - - /// - /// Retrieve the resource from the api. - /// - Get = 1 << 1, - - /// - /// List resources on the api. - /// - List = 1 << 2, - - /// - /// Watch for events on resources. - /// - Watch = 1 << 3, - - /// - /// Create new instances of the resource. - /// - Create = 1 << 4, - - /// - /// Update existing resources. - /// - Update = 1 << 5, - - /// - /// Patch resources. - /// - Patch = 1 << 6, - - /// - /// Delete resources on the api. - /// - Delete = 1 << 7, -} diff --git a/_old/src/KubeOps/Operator/Serialization/EntitySerializer.cs b/_old/src/KubeOps/Operator/Serialization/EntitySerializer.cs deleted file mode 100644 index defb0f43..00000000 --- a/_old/src/KubeOps/Operator/Serialization/EntitySerializer.cs +++ /dev/null @@ -1,14 +0,0 @@ -using k8s; - -namespace KubeOps.Operator.Serialization; - -internal static class EntitySerializer -{ - public static string Serialize(object @object, SerializerOutputFormat format = default) - => format switch - { - SerializerOutputFormat.Yaml => KubernetesYaml.Serialize(@object), - SerializerOutputFormat.Json => KubernetesJson.Serialize(@object), - _ => throw new ArgumentOutOfRangeException(nameof(format)), - }; -} diff --git a/_old/src/KubeOps/Operator/Serialization/SerializerOutputFormat.cs b/_old/src/KubeOps/Operator/Serialization/SerializerOutputFormat.cs deleted file mode 100644 index 347b1f37..00000000 --- a/_old/src/KubeOps/Operator/Serialization/SerializerOutputFormat.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace KubeOps.Operator.Serialization; - -internal enum SerializerOutputFormat -{ - /// - /// Return the generated output in yaml format. - /// - Yaml, - - /// - /// Return the generated output in json format. - /// - Json, -} diff --git a/_old/src/KubeOps/Operator/ServiceCollectionExtensions.cs b/_old/src/KubeOps/Operator/ServiceCollectionExtensions.cs deleted file mode 100644 index 6922830f..00000000 --- a/_old/src/KubeOps/Operator/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using KubeOps.Operator.Builder; - -namespace KubeOps.Operator; - -/// -/// Extensions for . -/// -public static class ServiceCollectionExtensions -{ - /// - /// Add the kubernetes operator to the dependency injection - /// and configure the operator. - /// - /// . - /// An optional configure action for adjusting settings in the operator. - /// An for further configuration and chaining. - public static IOperatorBuilder AddKubernetesOperator( - this IServiceCollection services, - Action? configure = null) - { - var settings = new OperatorSettings(); - configure?.Invoke(settings); - return AddKubernetesOperator(services, settings); - } - - /// - /// Add the kubernetes operator to the dependency injection - /// and configure the operator. - /// - /// . - /// An instance of the operator settings to use. - /// An for further configuration and chaining. - public static IOperatorBuilder AddKubernetesOperator( - this IServiceCollection services, - OperatorSettings settings) => new OperatorBuilder(services).AddOperatorBase(settings); -} diff --git a/_old/src/KubeOps/Operator/Util/StringExtensions.cs b/_old/src/KubeOps/Operator/Util/StringExtensions.cs deleted file mode 100644 index 48e24b88..00000000 --- a/_old/src/KubeOps/Operator/Util/StringExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace KubeOps.Operator.Util; - -internal static class StringExtensions -{ - private const byte MaxNameLength = 254; - - internal static string ToCamelCase(this string value) => - string.IsNullOrWhiteSpace(value) || char.IsLower(value[0]) - ? value - : char.ToLowerInvariant(value[0]) + value[1..]; - - internal static string TrimWebhookName(this string name, string prefix = "") - { - var tmp = prefix + name; - tmp = tmp.Length < MaxNameLength ? tmp : tmp[..MaxNameLength]; - return tmp.ToLowerInvariant(); - } - - internal static string FormatWebhookUrl(this string baseUrl, string endpoint) - { - if (!baseUrl.StartsWith("https://")) - { - throw new ArgumentException(@"The base url must start with ""https://""."); - } - - return baseUrl.Trim().TrimEnd('/') + endpoint; - } -}