Skip to content

Commit 0b65868

Browse files
authored
feat(webhooks): Add mutation webhooks. (#167)
This closes #135. This adds the possibility to have mutation webhooks which are able to modify an object before it is validated and stored into the master api. BREAKING CHANGE: `ValidatedOperations` is renamed to `AdmissionOperations`. Signed-off-by: Christoph Bühler <[email protected]>
1 parent cd182ee commit 0b65868

Some content is hidden

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

47 files changed

+877
-481
lines changed

config/CodeAnalysis.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
<TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
1212
</PropertyGroup>
1313

14-
</Project>
14+
</Project>

docs/docs/webhooks.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ of the master api. Those are documented on the
66

77
`KubeOps` supports the following webhooks out of the box:
88
- Validator / Validation
9+
- Mutator / Mutation
910

1011
The following documentation should give the user an overview
1112
on how to implement a webhook what this implies to the written operator.
@@ -82,13 +83,13 @@ It is suggested one uses `Docker Desktop` with kubernetes.
8283
The general idea of this webhook type is to validate an entity
8384
before it is definitely created / updated or deleted.
8485

85-
Webhooks are registered in a **scoped** maner to the DI system.
86+
Webhooks are registered in a **scoped** manner to the DI system.
8687
They behave like asp.net api controller.
8788

88-
The implementation of a webhook is fairly simple:
89+
The implementation of a validator is fairly simple:
8990
- Create a class somewhere in your project.
9091
- Implement the @"KubeOps.Operator.Webhooks.IValidationWebhook`1" interface.
91-
- Define the @"KubeOps.Operator.Webhooks.IValidationWebhook`1.Operations"
92+
- Define the @"KubeOps.Operator.Webhooks.IAdmissionWebhook`2.Operations"
9293
(from the interface) that the validator is interested in.
9394
- Overwrite the corresponding methods.
9495

@@ -112,7 +113,7 @@ as well as a custom error message that is presented to the user.
112113
```c#
113114
public class TestValidator : IValidationWebhook<EntityClass>
114115
{
115-
public ValidatedOperations Operations => ValidatedOperations.Create | ValidatedOperations.Update;
116+
public AdmissionOperations Operations => AdmissionOperations.Create | AdmissionOperations.Update;
116117

117118
public ValidationResult Create(EntityClass newEntity, bool dryRun) =>
118119
CheckSpec(newEntity)
@@ -127,3 +128,34 @@ public class TestValidator : IValidationWebhook<EntityClass>
127128
private static bool CheckSpec(EntityClass entity) => entity.Spec.Username != "foobar";
128129
}
129130
```
131+
132+
## Mutation webhook
133+
134+
Mutators are similar to validators but instead of defining if an object is
135+
valid or not, they are able to modify an object on the fly. The result
136+
of a mutator may generate a JSON Patch (http://jsonpatch.com) that patches
137+
the object that is later passed to the validators and to the Kubernetes
138+
API.
139+
140+
The implementation of a mutator is fairly simple:
141+
- Create a class somewhere in your project.
142+
- Implement the @"KubeOps.Operator.Webhooks.IMutationWebhook`1" interface.
143+
- Define the @"KubeOps.Operator.Webhooks.IAdmissionWebhook`2.Operations"
144+
(from the interface) that the validator is interested in.
145+
- Overwrite the corresponding methods.
146+
147+
> [!WARNING]
148+
> The interface contains default implementations for _ALL_ methods.
149+
> The default of the async methods are to call the sync ones.
150+
> The default of the sync methods is to return a "not implemented"
151+
> result.
152+
> The async methods take precedence over the synchronous ones.
153+
154+
The return value of the mutation methods do indicate if
155+
there has been a change in the model or not. If there is no
156+
change, return a result from @"KubeOps.Operator.Webhooks.MutationResult.NoChanges"
157+
and if there are changes, modify the object that is passed to the
158+
method and return the changed object with
159+
@"KubeOps.Operator.Webhooks.MutationResult.Modified(System.Object)".
160+
The system then calculates the diff and creates a JSON patch for
161+
the object.

src/KubeOps.Templates/KubeOps.Templates.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<Import Project="..\..\config\Common.targets"/>
4-
<Import Project="..\..\config\CodeAnalysis.targets"/>
3+
<Import Project="..\..\config\Common.targets" />
4+
<Import Project="..\..\config\CodeAnalysis.targets" />
55

66
<PropertyGroup>
77
<IsPackable>true</IsPackable>
@@ -24,8 +24,8 @@
2424
</PropertyGroup>
2525

2626
<ItemGroup>
27-
<Content Include="Templates\**\*" Exclude="Templates\**\bin\**;Templates\**\obj\**"/>
28-
<Compile Remove="**\*"/>
27+
<Content Include="Templates\**\*" Exclude="Templates\**\bin\**;Templates\**\obj\**" />
28+
<Compile Remove="**\*" />
2929
</ItemGroup>
3030

3131
</Project>

src/KubeOps.Templates/Templates/EmptyOperator.CSharp/GeneratedOperatorProject.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

9-
</Project>
9+
</Project>

src/KubeOps.Templates/Templates/Operator.CSharp/GeneratedOperatorProject.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

9-
</Project>
9+
</Project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using GeneratedOperatorProject.Entities;
2+
using KubeOps.Operator.Webhooks;
3+
using Microsoft.AspNetCore.Http;
4+
5+
namespace GeneratedOperatorProject.Webhooks
6+
{
7+
public class DemoMutator : IMutationWebhook<V1DemoEntity>
8+
{
9+
public AdmissionOperations Operations => AdmissionOperations.Create;
10+
11+
public MutationResult Create(V1DemoEntity newEntity, bool dryRun)
12+
{
13+
newEntity.Spec.Username = "not foobar";
14+
return MutationResult.Modified(newEntity);
15+
}
16+
}
17+
}

src/KubeOps.Templates/Templates/Operator.CSharp/Webhooks/DemoValidator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace GeneratedOperatorProject.Webhooks
66
{
77
public class DemoValidator : IValidationWebhook<V1DemoEntity>
88
{
9-
public ValidatedOperations Operations => ValidatedOperations.Create;
9+
public AdmissionOperations Operations => AdmissionOperations.Create;
1010

1111
public ValidationResult Create(V1DemoEntity newEntity, bool dryRun)
1212
=> newEntity.Spec.Username == "forbiddenUsername"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace GeneratedOperatorProject.Webhooks
2+
3+
open GeneratedOperatorProject.Entities
4+
open KubeOps.Operator.Webhooks
5+
open Microsoft.AspNetCore.Http
6+
7+
type DemoMutator() =
8+
interface IMutationWebhook<V1DemoEntity> with
9+
member this.Operations = AdmissionOperations.Create
10+
11+
member this.Create(newEntity, _) =
12+
newEntity.Spec.Username <- "not foobar"
13+
MutationResult.Modified(newEntity)

src/KubeOps.Templates/Templates/Operator.FSharp/Webhooks/DemoValidator.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ open Microsoft.AspNetCore.Http
66

77
type DemoValidator() =
88
interface IValidationWebhook<V1DemoEntity> with
9-
member this.Operations = ValidatedOperations.Create
9+
member this.Operations = AdmissionOperations.Create
1010

1111
member this.Create(newEntity, _) =
1212
if newEntity.Spec.Username = "forbiddenUsername"

src/KubeOps/KubeOps.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
<ItemGroup>
2727
<PackageReference Include="CompareNETObjects" Version="4.72.0" />
28-
<PackageReference Include="DotnetKubernetesClient" Version="1.1.0" />
28+
<PackageReference Include="DotnetKubernetesClient" Version="1.1.1" />
29+
<PackageReference Include="JsonDiffPatch" Version="2.0.52" />
2930
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0" />
3031
<PackageReference Include="McMaster.Extensions.Hosting.CommandLine" Version="3.1.0" />
3132
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.3" />

0 commit comments

Comments
 (0)