Skip to content

Commit aca97e1

Browse files
author
Christoph Bühler
committed
feat(webhook-generator): add mutation webhook configs.
1 parent 7841fe9 commit aca97e1

File tree

6 files changed

+111
-33
lines changed

6 files changed

+111
-33
lines changed

src/KubeOps.Cli/Commands/Generator/WebhookOperatorGenerator.cs

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -176,47 +176,91 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
176176
{ Exists: false } => throw new FileNotFoundException($"The file {file.Name} does not exist."),
177177
_ => throw new NotSupportedException("Only *.csproj and *.sln files are supported."),
178178
};
179-
var validatedEntities = parser.GetValidatedEntities().ToList();
179+
180+
var caBundle = Encoding.ASCII.GetBytes(Convert.ToBase64String(Encoding.ASCII.GetBytes(caCert.ToPem())));
181+
182+
var validationWebhooks = parser.GetValidatedEntities().ToList();
180183
var validatorConfig = new V1ValidatingWebhookConfiguration(
181184
metadata: new V1ObjectMeta(name: "validators"),
182185
webhooks: new List<V1ValidatingWebhook>()).Initialize();
183186

184-
foreach (var entity in validatedEntities)
187+
foreach (var hook in validationWebhooks)
185188
{
186189
validatorConfig.Webhooks.Add(new V1ValidatingWebhook
187190
{
188-
Name = $"validate.{entity.Metadata.SingularName}.{entity.Metadata.Group}.{entity.Metadata.Version}",
191+
Name = $"validate.{hook.Metadata.SingularName}.{hook.Metadata.Group}.{hook.Metadata.Version}",
189192
MatchPolicy = "Exact",
190193
AdmissionReviewVersions = new[] { "v1" },
191194
SideEffects = "None",
192195
Rules = new[]
193196
{
194197
new V1RuleWithOperations
195198
{
196-
Operations = entity.GetOperations(),
197-
Resources = new[] { entity.Metadata.PluralName },
198-
ApiGroups = new[] { entity.Metadata.Group },
199-
ApiVersions = new[] { entity.Metadata.Version },
199+
Operations = hook.GetOperations(),
200+
Resources = new[] { hook.Metadata.PluralName },
201+
ApiGroups = new[] { hook.Metadata.Group },
202+
ApiVersions = new[] { hook.Metadata.Version },
200203
},
201204
},
202205
ClientConfig = new Admissionregistrationv1WebhookClientConfig
203206
{
204-
CaBundle =
205-
Encoding.ASCII.GetBytes(Convert.ToBase64String(Encoding.ASCII.GetBytes(caCert.ToPem()))),
207+
CaBundle = caBundle,
206208
Service = new Admissionregistrationv1ServiceReference
207209
{
208-
Name = "operator", Path = entity.ValidatorPath,
210+
Name = "operator",
211+
Path = hook.WebhookPath,
209212
},
210213
},
211214
});
212215
}
213216

214-
if (validatedEntities.Any())
217+
if (validationWebhooks.Any())
215218
{
216219
result.Add(
217220
$"validators.{format.ToString().ToLowerInvariant()}", validatorConfig);
218221
}
219222

223+
var mutationWebhooks = parser.GetMutatedEntities().ToList();
224+
var mutatorConfig = new V1MutatingWebhookConfiguration(
225+
metadata: new V1ObjectMeta(name: "mutators"),
226+
webhooks: new List<V1MutatingWebhook>()).Initialize();
227+
228+
foreach (var hook in mutationWebhooks)
229+
{
230+
mutatorConfig.Webhooks.Add(new V1MutatingWebhook
231+
{
232+
Name = $"mutate.{hook.Metadata.SingularName}.{hook.Metadata.Group}.{hook.Metadata.Version}",
233+
MatchPolicy = "Exact",
234+
AdmissionReviewVersions = new[] { "v1" },
235+
SideEffects = "None",
236+
Rules = new[]
237+
{
238+
new V1RuleWithOperations
239+
{
240+
Operations = hook.GetOperations(),
241+
Resources = new[] { hook.Metadata.PluralName },
242+
ApiGroups = new[] { hook.Metadata.Group },
243+
ApiVersions = new[] { hook.Metadata.Version },
244+
},
245+
},
246+
ClientConfig = new Admissionregistrationv1WebhookClientConfig
247+
{
248+
CaBundle = caBundle,
249+
Service = new Admissionregistrationv1ServiceReference
250+
{
251+
Name = "operator",
252+
Path = hook.WebhookPath,
253+
},
254+
},
255+
});
256+
}
257+
258+
if (mutationWebhooks.Any())
259+
{
260+
result.Add(
261+
$"mutators.{format.ToString().ToLowerInvariant()}", mutatorConfig);
262+
}
263+
220264
result.Add(
221265
$"kustomization.{format.ToString().ToLowerInvariant()}",
222266
new KustomizationConfig
@@ -229,6 +273,9 @@ internal static async Task Handler(IAnsiConsole console, InvocationContext ctx)
229273
validatorConfig.Webhooks.Any()
230274
? $"validators.{format.ToString().ToLowerInvariant()}"
231275
: string.Empty,
276+
mutatorConfig.Webhooks.Any()
277+
? $"mutators.{format.ToString().ToLowerInvariant()}"
278+
: string.Empty,
232279
}.Where(s => !string.IsNullOrWhiteSpace(s)).ToList(),
233280
CommonLabels = new Dictionary<string, string> { { "operator-element", "operator-instance" }, },
234281
ConfigMapGenerator = new List<KustomizationConfigMapGenerator>

src/KubeOps.Cli/Transpilation/AssemblyLoader.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
using KubeOps.Abstractions.Entities.Attributes;
88
using KubeOps.Abstractions.Rbac;
9+
using KubeOps.Operator.Web.Webhooks.Mutation;
910
using KubeOps.Operator.Web.Webhooks.Validation;
1011
using KubeOps.Transpiler;
1112

@@ -165,13 +166,21 @@ public static IEnumerable<CustomAttributeData> GetRbacAttributes(this MetadataLo
165166
}
166167
}
167168

168-
public static IEnumerable<ValidatedEntity> GetValidatedEntities(this MetadataLoadContext context) => context
169+
public static IEnumerable<ValidationWebhook> GetValidatedEntities(this MetadataLoadContext context) => context
169170
.GetAssemblies()
170171
.SelectMany(a => a.DefinedTypes)
171172
.Where(t => t.BaseType?.Name == typeof(ValidationWebhook<>).Name &&
172173
t.BaseType?.Namespace == typeof(ValidationWebhook<>).Namespace)
173174
.Distinct()
174-
.Select(t => new ValidatedEntity(t, context.ToEntityMetadata(t.BaseType!.GenericTypeArguments[0]).Metadata));
175+
.Select(t => new ValidationWebhook(t, context.ToEntityMetadata(t.BaseType!.GenericTypeArguments[0]).Metadata));
176+
177+
public static IEnumerable<MutationWebhook> GetMutatedEntities(this MetadataLoadContext context) => context
178+
.GetAssemblies()
179+
.SelectMany(a => a.DefinedTypes)
180+
.Where(t => t.BaseType?.Name == typeof(MutationWebhook<>).Name &&
181+
t.BaseType?.Namespace == typeof(MutationWebhook<>).Namespace)
182+
.Distinct()
183+
.Select(t => new MutationWebhook(t, context.ToEntityMetadata(t.BaseType!.GenericTypeArguments[0]).Metadata));
175184

176185
[GeneratedRegex(".*")]
177186
private static partial Regex DefaultRegex();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Reflection;
2+
3+
using KubeOps.Abstractions.Entities;
4+
5+
namespace KubeOps.Cli.Transpilation;
6+
7+
internal abstract record BaseWebhook(TypeInfo Webhook, EntityMetadata Metadata)
8+
{
9+
private bool HasCreate => Webhook.DeclaredMembers.Any(m => m.Name.StartsWith("Create"));
10+
11+
private bool HasUpdate => Webhook.DeclaredMembers.Any(m => m.Name.StartsWith("Update"));
12+
13+
private bool HasDelete => Webhook.DeclaredMembers.Any(m => m.Name.StartsWith("Delete"));
14+
15+
public abstract string WebhookPath { get; }
16+
17+
public string[] GetOperations() =>
18+
new[] { HasCreate ? "CREATE" : null, HasUpdate ? "UPDATE" : null, HasDelete ? "DELETE" : null, }
19+
.Where(o => o is not null).ToArray()!;
20+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Reflection;
2+
3+
using KubeOps.Abstractions.Entities;
4+
5+
namespace KubeOps.Cli.Transpilation;
6+
7+
internal record MutationWebhook(TypeInfo Validator, EntityMetadata Metadata) : BaseWebhook(Validator, Metadata)
8+
{
9+
public override string WebhookPath =>
10+
$"/mutate/{Validator.BaseType!.GenericTypeArguments[0].Name.ToLowerInvariant()}";
11+
}

src/KubeOps.Cli/Transpilation/ValidatedEntity.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Reflection;
2+
3+
using KubeOps.Abstractions.Entities;
4+
5+
namespace KubeOps.Cli.Transpilation;
6+
7+
internal record ValidationWebhook(TypeInfo Validator, EntityMetadata Metadata) : BaseWebhook(Validator, Metadata)
8+
{
9+
public override string WebhookPath =>
10+
$"/validate/{Validator.BaseType!.GenericTypeArguments[0].Name.ToLowerInvariant()}";
11+
}

0 commit comments

Comments
 (0)