Skip to content

Commit 84d6e8a

Browse files
committed
docs: Adjust documentation according to breaking changes.
1 parent 163c18b commit 84d6e8a

25 files changed

+322
-323
lines changed

docs/docs/controller.md

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ resources on kubernetes and queueing of the events.
77
When you want to create a controller for your (or any) entity,
88
read the following instructions.
99

10-
When you have controllers, don't forget to register them with
11-
<xref:KubeOps.Operator.Builder.IOperatorBuilder.AddController``1>
12-
to the DI system.
10+
When you have controllers, they are automatically added to the
11+
DI system via their <xref:KubeOps.Operator.Controller.IResourceController`1> interface.
12+
13+
Controllers are registered as **scoped** elements in the DI system.
14+
Which means, they basically behave like asp.net api controllers.
15+
You can use dependency injection with all types of dependencies.
1316

1417
## Controller instance
1518

@@ -18,16 +21,14 @@ or you want to reconcile a given entity (from the `k8s.Models` namespace,
1821
e.g. `V1ConfigMap`) you need to create a controller class
1922
as you would do for a MVC or API controller in asp.net.
2023

21-
Make sure you have the correct baseclass
22-
(<xref:KubeOps.Operator.Controller.ResourceControllerBase`1>)
23-
inherited.
24+
Make sure you implement the <xref:KubeOps.Operator.Controller.IResourceController`1> interface.
2425

2526
```csharp
2627
[EntityRbac(typeof(MyCustomEntity), Verbs = RbacVerb.All)]
27-
public class FooCtrl: ResourceControllerBase<MyCustomEntity>
28+
public class FooCtrl : IResourceController<MyCustomEntity>
2829
{
29-
protected override async Task<TimeSpan?> Created(MyCustomEntity resource){}
30-
// overwrite other methods here.
30+
// Implement the needed methods here.
31+
// The interface provides default implementation which do a NOOP.
3132
// Possible overwrites:
3233
// "Created" (i.e. when the operator sees the entity for the first time),
3334
// "Updated" (i.e. when the operator knows the entity and it was updated),
@@ -86,27 +87,27 @@ which takes a list of api groups, resources, versions and a selection of
8687

8788
## Requeue
8889

89-
The controller's methods have a return value of `TimeSpan?`. This means
90-
you can return a time span to automatically requeue the event for the
91-
given entity. If requeued and nothing changed, it will most likely fire
92-
a `NotModified` event.
90+
The controller's methods have a return value of <xref:KubeOps.Operator.Controller.Results.ResourceControllerResult>.
91+
There are multiple ways how a result of a controller can be created:
9392

94-
This can be useful if you want to periodically check for a database
95-
connection for example and update the status of a given entity.
93+
- `null`: The controller will not requeue your entity / event.
94+
- <xref:KubeOps.Operator.Controller.Results.ResourceControllerResult.RequeueEvent(System.TimeSpan)>:
95+
Return a result object with a <xref:System.TimeSpan> that will requeue
96+
the event and the entity after the time has passed.
9697

97-
If you return `null` in an event function, the event is not requeued.
98-
If you return a timespan, then the event is requeued after this delay.
98+
The requeue mechanism can be useful if you want to periodically check for a database
99+
connection for example and update the status of a given entity.
99100

100101
```csharp
101102
/* snip... */
102-
protected override async Task<TimeSpan?> Created(MyCustomEntity resource){
103-
// do something useful.
104-
return TimeSpan.FromSeconds(15); // This will retrigger an event in 15 secs.
103+
public Task<ResourceControllerResult> CreatedAsync(V1TestEntity resource)
104+
{
105+
return Task.FromResult(ResourceControllerResult.RequeueEvent(TimeSpan.FromSeconds(15)); // This will requeue the event in 15 seconds.
105106
}
106107

107-
protected override async Task<TimeSpan?> Updated(MyCustomEntity resource){
108-
// do something useful.
109-
return null; // This will not retrigger an event.
108+
public Task<ResourceControllerResult> CreatedAsync(V1TestEntity resource)
109+
{
110+
return Task.FromResult<ResourceControllerResult>(null); // This wont trigger a requeue.
110111
}
111112
/* snip... */
112113
```
@@ -117,22 +118,11 @@ If the function throws an error, the event is requeued with an exponential backo
117118

118119
```csharp
119120
/* snip... */
120-
protected override async Task<TimeSpan?> Created(MyCustomEntity resource){
121+
public Task<ResourceControllerResult> CreatedAsync(V1TestEntity resource)
121122
// do something useful.
122123
throw new Exception("¯\\_(ツ)_/¯");
123124
}
124125
/* snip... */
125126
```
126127

127-
The backoff function is defined as follows:
128-
129-
```csharp
130-
private const double MaxRetrySeconds = 64;
131-
private TimeSpan ExponentialBackoff(int retryCount) => TimeSpan
132-
.FromSeconds(Math.Min(Math.Pow(2, retryCount), MaxRetrySeconds))
133-
.Add(TimeSpan.FromMilliseconds(_rnd.Next(0, 1000)));
134-
```
135-
136-
Which means with each retry, it calculates the new backoff time
137-
to a max of 64. To each of those times a random number of milliseconds
138-
is added to add a certain fuzzying.
128+
Each event that errors will be retried **four times**.

docs/docs/entities.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Custom Entities
22

3+
The words `entity` and `resource` are kind of interchangeable. It strongly
4+
depends on the context. The resource is the type of an object in kubernetes
5+
which is defined by the default api or a CRD. While an entity is a class
6+
in C# of such a resource. (CRD means "custom resource definition").
7+
38
To write your own kubernetes entities, use the interfaces
49
provided by `k8s` or use the <xref:KubeOps.Operator.Entities.CustomKubernetesEntity>.
510

@@ -39,7 +44,7 @@ If you don't use the <xref:KubeOps.Operator.Entities.CustomKubernetesEntity`1> b
3944

4045
### Ignoring Entities
4146

42-
There are usecases when you want to model / watch a custom entity from another
47+
There are use-cases when you want to model / watch a custom entity from another
4348
software engineer that are not part of the base models in `k8s`.
4449

4550
To prevent the generator from creating yamls for CRDs you don't own, use

docs/docs/events.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ IEventManager manager = services.GetRequiredService<IEventManager>;
2424
// If the event was previously published, it is fetched
2525
// and the "count" number is increased. This essentially
2626
// creates an event-series.
27-
await manager.Publish(resource, "reason", "my fancy message");
27+
await manager.PublishAsync(resource, "reason", "my fancy message");
2828
```
2929

3030
If you want full control over the event:
@@ -39,19 +39,19 @@ var @event = new Corev1Event
3939

4040
// Publish the event.
4141
// This essentially calls IKubernetesClient.Save.
42-
await manager.Publish(@event);
42+
await manager.PublishAsync(@event);
4343
```
4444

4545
### Use publisher delegates
4646

4747
If you don't want to call the
48-
@"KubeOps.Operator.Events.IEventManager.Publish(k8s.IKubernetesObject{k8s.Models.V1ObjectMeta},System.String,System.String,KubeOps.Operator.Events.EventType)"
48+
@"KubeOps.Operator.Events.IEventManager.PublishAsync(k8s.IKubernetesObject{k8s.Models.V1ObjectMeta},System.String,System.String,KubeOps.Operator.Events.EventType)"
4949
all the time with the same arguments, you can create delegates.
5050

5151
There exist two different delegates:
52-
- @"KubeOps.Operator.Events.IEventManager.StaticPublisher": Predefined event
52+
- @"KubeOps.Operator.Events.IEventManager.AsyncStaticPublisher": Predefined event
5353
on a predefined resource.
54-
- @"KubeOps.Operator.Events.IEventManager.Publisher": Predefined event
54+
- @"KubeOps.Operator.Events.IEventManager.AsyncPublisher": Predefined event
5555
on a variable resource.
5656

5757
Both are created with their specific overload:
@@ -80,22 +80,21 @@ The dynamic publisher can be used to predefine the event for your resources.
8080

8181
As an example in a controller:
8282
```c#
83-
public class TestController : ResourceControllerBase<V1TestEntity>
83+
public class TestController : IResourceController<V1TestEntity>
8484
{
8585
private readonly IEventManager.Publisher _publisher;
8686

87-
public TestController(IEventManager eventManager, IResourceServices<V1TestEntity> services)
88-
: base(services)
87+
public TestController(IEventManager eventManager)
8988
{
9089
_publisher = eventManager.CreatePublisher("reason", "my fancy message");
9190
}
9291

93-
protected override async Task<TimeSpan?> Created(V1TestEntity resource)
92+
public Task<ResourceControllerResult> CreatedAsync(V1TestEntity resource)
9493
{
9594
// Here, the event is published with predefined strings
9695
// but for a "variable" resource.
9796
await _publisher(resource);
98-
return await base.Created(resource);
97+
return Task.FromResult<ResourceControllerResult>(null);
9998
}
10099
}
101100
```

docs/docs/features.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ As of now, the operator sdk supports - roughly - the following features:
1414
- NotModified
1515
- StatusModified
1616
- Deleted
17-
- AddFinalizer
1817
- Finalizers for entities
1918
- Webhooks
2019
- Validation / validators

docs/docs/finalizer.md

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,65 @@
33
A finalizer is a special type of software that can asynchronously
44
cleanup stuff for an entity that is being deleted.
55

6-
A finalizer is registered as an identifier in the kubernetes
7-
resource (i.e. in the yaml / json structure) and an object
6+
A finalizer is registered as an identifier in a kubernetes
7+
object (i.e. in the yaml / json structure) and the object
88
wont be removed from the api until all finalizers are removed.
99

10-
If you write finalizer, don't forget to register them with
11-
<xref:KubeOps.Operator.Builder.IOperatorBuilder.AddFinalizer``1>
12-
to the DI system.
10+
If you write finalizer, they will be automatically added to the
11+
DI system via their type <xref:KubeOps.Operator.Finalizer.IResourceFinalizer`1>
1312

1413
## Write a finalizer
1514

16-
Use the correct base class (<xref:KubeOps.Operator.Finalizer.ResourceFinalizerBase`1>).
15+
Use the correct interface (<xref:KubeOps.Operator.Finalizer.IResourceFinalizer`1>).
1716

1817
A finalizer can be as simple as:
1918

2019
```csharp
21-
public class FooFinalizer : ResourceFinalizerBase<Foo>
20+
public class TestEntityFinalizer : IResourceFinalizer<V1TestEntity>
2221
{
23-
public override async Task Finalize(Foo resource)
22+
private readonly IManager _manager;
23+
24+
public TestEntityFinalizer(IManager manager)
2425
{
25-
// do something with the resource.
26-
// like deleting a database.
26+
_manager = manager;
27+
}
28+
29+
public Task FinalizeAsync(V1TestEntity resource)
30+
{
31+
_manager.Finalized(resource);
32+
return Task.CompletedTask;
2733
}
2834
}
2935
```
3036

37+
The interface also provides a way of overwriting the
38+
<xref:KubeOps.Operator.Finalizer.IResourceFinalizer`1.Identifier> of the finalizer if you feed like it.
39+
3140
When the finalizer successfully completed his job, it is automatically removed
32-
from the finalizers list of the resource. The finalizers are registered
33-
as transient resources in DI.
41+
from the finalizers list of the entity. The finalizers are registered
42+
as scoped resources in DI.
3443

3544
## Register a finalizer
3645

3746
To attach a finalizer for a resource, call the
38-
<xref:KubeOps.Operator.Controller.ResourceControllerBase`1.AttachFinalizer``1(`0)>
47+
<xref:KubeOps.Operator.Finalizer.IFinalizerManager`1.RegisterFinalizerAsync``1(`0)>
3948
method in the controller during reconciliation.
4049

4150
```csharp
42-
public class TestController : ResourceControllerBase<V1TestEntity>
51+
public class TestController : IResourceController<V1TestEntity>
4352
{
44-
protected override async Task<TimeSpan?> Created(V1TestEntity resource)
53+
private readonly IFinalizerManager<V1TestEntity> _manager;
54+
55+
public TestController(IFinalizerManager<V1TestEntity> manager)
56+
{
57+
_manager = manager;
58+
}
59+
60+
public async Task<ResourceControllerResult> CreatedAsync(V1TestEntity resource)
4561
{
46-
await AttachFinalizer<TestEntityFinalizer>(resource);
47-
return await base.Created(resource);
62+
// The type MyFinalizer must be an IResourceFinalizer<V1TestEntity>
63+
await _manager.RegisterFinalizerAsync<MyFinalizer>(resource);
64+
return null;
4865
}
4966
}
5067
```

docs/docs/getting_started.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ that activate and start the operator as a web application.
1010

1111
## Terminology
1212

13-
- `Entity`: A (C#) model - an entity - that is used in kubernetes. An entity defines the CRD.
14-
- `Resource`: An instance of an entity.
13+
- `Entity`: A (C#) model - an entity - that is used in kubernetes.
14+
An entity is the class for a kubernetes resource.
15+
- `Resource` (or `TResource`): The type of a kubernetes resource.
1516
- `Controller` or `ResourceController`: An instance of a resource manager
1617
that is responsible for the reconciliation of an entity.
1718
- `Finalizer`: A special resource manager that is attached to the entity
1819
via identifier. The finalizers are called when an entity is deleted
1920
on kubernetes.
21+
- `Validator`: An implementation for a validation admission webhook.
2022
- `CRD`: CustomResourceDefinition of kubernetes.
2123

2224
## How To Start
@@ -82,9 +84,7 @@ public class Startup
8284
public void ConfigureServices(IServiceCollection services)
8385
{
8486
services
85-
.AddKubernetesOperator() // config / settings here
86-
.AddFinalizer<TestEntityFinalizer>()
87-
.AddController<TestController>(); // Add controllers / finalizers / ... here
87+
.AddKubernetesOperator(); // config / settings here
8888
8989
// your own dependencies
9090
services.AddTransient<IManager, TestManager.TestManager>();

docs/docs/testing.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ have a look at the test code in the repository:
1212
> For normal unit testing, you can just mock all the things.
1313
1414
The main entry point for testing your custom operator is the
15-
@"KubeOps.Testing.KubernetesOperatorFactory`1". It is ment to be
15+
@"KubeOps.Testing.KubernetesOperatorFactory`1". It is meant to be
1616
injected into your test.
1717

1818
> [!NOTE]
@@ -24,34 +24,34 @@ The following steps are needed for integration testing the controller:
2424

2525
- Create a `TestStartup.cs` file (or any other name you want)
2626
- Inject the @"KubeOps.Testing.KubernetesOperatorFactory`1"
27-
- Use the mocked client / queues to test your operator
27+
- Use the mocked client and helper functions to test your operator
2828

2929
## Test Startup
3030

3131
This file is very similar to a "normal" `Startup.cs` file of an
3232
asp.net application. Either you subclass it and replace your test mocked
3333
services, or you create a new one.
3434

35-
[!code-csharp[TestStartup.cs](../../tests/KubeOps.TestOperator.Test/TestStartup.cs?highlight=20-21)]
35+
[!code-csharp[TestStartup.cs](../../tests/KubeOps.TestOperator.Test/TestStartup.cs)]
3636

3737
## Mocked elements
3838

3939
The main part of this operator factory does mock the used kubernetes client
40-
and the resource event queues.
40+
and helper functions to enqueue events and finalizer events.
4141

4242
Both mocked elements can be retrieved via the operator factory with:
4343

44-
- @"KubeOps.Testing.KubernetesOperatorFactory`1.GetMockedEventQueue``1"
4544
- @"KubeOps.Testing.KubernetesOperatorFactory`1.MockedKubernetesClient"
45+
- @"KubeOps.Testing.KubernetesOperatorFactory`1.EnqueueEvent``1(KubeOps.Operator.Kubernetes.ResourceEventType,``0)"
46+
- @"KubeOps.Testing.KubernetesOperatorFactory`1.EnqueueFinalization``1(``0)"
4647

47-
### Mocked event queue
48+
### Mocked events
4849

49-
The event queue does not use a channel to read and write event but directly fire
50-
the given events.
50+
With the mentioned factory functions (@"KubeOps.Testing.KubernetesOperatorFactory`1.EnqueueEvent``1(KubeOps.Operator.Kubernetes.ResourceEventType,``0)"
51+
and @"KubeOps.Testing.KubernetesOperatorFactory`1.EnqueueFinalization``1(``0)")
52+
one can fire events for entities. This can be used to test your controllers.
5153

52-
Also, the @"KubeOps.Operator.Queue.IResourceEventQueue`1.Enqueue(`0,System.Nullable{System.TimeSpan})"
53-
method does not actually enqueue anything but just adds the resource to a list
54-
of resources.
54+
The controllers are normally instantiated via the scope of the DI system.
5555

5656
### Mocked IKubernetesClient
5757

@@ -73,4 +73,4 @@ You probably need to set the solution relative content root for
7373
asp.net testing. But then you can run the factory
7474
and create a test.
7575

76-
[!code-csharp[TestStartup.cs](../../tests/KubeOps.TestOperator.Test/TestController.Test.cs?range=10-31,84&highlight=7,13)]
76+
[!code-csharp[TestStartup.cs](../../tests/KubeOps.TestOperator.Test/TestController.Test.cs)]

docs/docs/webhooks.md

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,15 @@ It is suggested one uses `Docker Desktop` with kubernetes.
8282
The general idea of this webhook type is to validate an entity
8383
before it is definitely created / updated or deleted.
8484

85+
Webhooks are registered in a **scoped** maner to the DI system.
86+
They behave like asp.net api controller.
87+
8588
The implementation of a webhook is fairly simple:
8689
- Create a class somewhere in your project.
8790
- Implement the @"KubeOps.Operator.Webhooks.IValidationWebhook`1" interface.
88-
- Define the @"KubeOps.Operator.Webhooks.IValidationWebhook.Operations"
91+
- Define the @"KubeOps.Operator.Webhooks.IValidationWebhook`1.Operations"
8992
(from the interface) that the validator is interested in.
9093
- Overwrite the corresponding methods.
91-
- Register it in the @"KubeOps.Operator.Builder.IOperatorBuilder"
92-
with @"KubeOps.Operator.Builder.IOperatorBuilder.AddValidationWebhook``1".
9394

9495
> [!WARNING]
9596
> The interface contains default implementations for _ALL_ methods.
@@ -126,15 +127,3 @@ public class TestValidator : IValidationWebhook<EntityClass>
126127
private static bool CheckSpec(EntityClass entity) => entity.Spec.Username != "foobar";
127128
}
128129
```
129-
130-
And then register the webhook in `Startup.cs`:
131-
132-
```c#
133-
public void ConfigureServices(IServiceCollection services)
134-
{
135-
services
136-
.AddKubernetesOperator()
137-
// ...
138-
.AddValidationWebhook<TestValidator>();
139-
}
140-
```

0 commit comments

Comments
 (0)