diff --git a/src/KubeOps/Operator/Commands/Management/Webhooks/Install.cs b/src/KubeOps/Operator/Commands/Management/Webhooks/Install.cs index f048ffb8..9688c375 100644 --- a/src/KubeOps/Operator/Commands/Management/Webhooks/Install.cs +++ b/src/KubeOps/Operator/Commands/Management/Webhooks/Install.cs @@ -43,6 +43,13 @@ public Install( LongName = "ca-certs")] public string CaCertificatesPath { get; set; } = "/ca"; + [Option( + Description = + "If specified and set to true it will replace already existing webhooks", + ShortName = "r", + LongName = "replace-existing")] + public bool ReplaceExistingWebhooks { get; set; } + public async Task OnExecuteAsync(CommandLineApplication app) { var client = app.GetRequiredService(); @@ -116,7 +123,27 @@ await client.Create( validatorConfig.Metadata.OwnerReferences = new List { deployment.MakeOwnerReference(), }; } - await client.Save(validatorConfig); + if (ReplaceExistingWebhooks) + { + // var existingItems = await client.List(); + // var existingItem = existingItems.FirstOrDefault(item => item.Name() == validatorConfig.Name()); + var existingItem = await client.Get(validatorConfig.Name()); + if (existingItem != null) + { + await app.Out.WriteLineAsync("Validator existed, updating."); + await client.Update(existingItem); + } + else + { + await app.Out.WriteLineAsync("Validator didn't exist, creating."); + await client.Save(validatorConfig); + } + } + else + { + await app.Out.WriteLineAsync("Not updating validator, attempting to save."); + await client.Save(validatorConfig); + } await app.Out.WriteLineAsync("Create mutator definition."); var mutatorConfig = _mutatingWebhookConfigurationBuilder.BuildWebhookConfiguration(webhookConfig); @@ -125,7 +152,25 @@ await client.Create( mutatorConfig.Metadata.OwnerReferences = new List { deployment.MakeOwnerReference(), }; } - await client.Save(mutatorConfig); + if (ReplaceExistingWebhooks) + { + var existingItem = await client.Get(mutatorConfig.Name()); + if (existingItem != null) + { + await app.Out.WriteLineAsync("Mutator existed, updating."); + await client.Update(existingItem); + } + else + { + await app.Out.WriteLineAsync("Mutator didn't exist, creating."); + await client.Save(mutatorConfig); + } + } + else + { + await app.Out.WriteLineAsync("Not updating mutator, attempting to save."); + await client.Save(mutatorConfig); + } await app.Out.WriteLineAsync("Installed webhook service and admission configurations."); diff --git a/src/KubeOps/Operator/Webhooks/IConfigurableMutationWebhook.cs b/src/KubeOps/Operator/Webhooks/IConfigurableMutationWebhook.cs new file mode 100644 index 00000000..6aa11af6 --- /dev/null +++ b/src/KubeOps/Operator/Webhooks/IConfigurableMutationWebhook.cs @@ -0,0 +1,15 @@ +using k8s.Models; + +namespace KubeOps.Operator.Webhooks; + +/// +/// Implement this interface to configure the MutatingWebhook object before it is applied to Kubernetes. +/// +public interface IConfigurableMutationWebhook +{ + /// + /// Called when building the MutatingWebhook to allow further customizations before it is applied. + /// + /// The MutatingWebhook that will be applied. + void Configure(V1MutatingWebhook webhook); +} diff --git a/src/KubeOps/Operator/Webhooks/IConfigurableValidationWebhook.cs b/src/KubeOps/Operator/Webhooks/IConfigurableValidationWebhook.cs new file mode 100644 index 00000000..d134a3d1 --- /dev/null +++ b/src/KubeOps/Operator/Webhooks/IConfigurableValidationWebhook.cs @@ -0,0 +1,15 @@ +using k8s.Models; + +namespace KubeOps.Operator.Webhooks; + +/// +/// Implement this interface to configure the ValidatingWebhook object before it is applied to Kubernetes. +/// +public interface IConfigurableValidationWebhook +{ + /// + /// Called when building the ValidatingWebhook to allow further customizations before it is applied. + /// + /// The ValidatingWebhook that will be applied. + void Configure(V1ValidatingWebhook webhook); +} diff --git a/src/KubeOps/Operator/Webhooks/MutatingWebhookBuilder.cs b/src/KubeOps/Operator/Webhooks/MutatingWebhookBuilder.cs index a3392406..b7b67544 100644 --- a/src/KubeOps/Operator/Webhooks/MutatingWebhookBuilder.cs +++ b/src/KubeOps/Operator/Webhooks/MutatingWebhookBuilder.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using k8s.Models; using KubeOps.KubernetesClient.Entities; using KubeOps.Operator.Builder; @@ -60,7 +60,7 @@ public List BuildWebhooks(WebhookConfig webhookConfig) var crd = entityType.ToEntityDefinition(); - return new V1MutatingWebhook + var webhook = new V1MutatingWebhook { Name = name.TrimWebhookName(), AdmissionReviewVersions = new[] { "v1" }, @@ -79,6 +79,13 @@ public List BuildWebhooks(WebhookConfig webhookConfig) }, ClientConfig = clientConfig, }; + + if (instance is IConfigurableMutationWebhook configurable) + { + configurable.Configure(webhook); + } + + return webhook; }) .ToList(); } diff --git a/src/KubeOps/Operator/Webhooks/ValidatingWebhookBuilder.cs b/src/KubeOps/Operator/Webhooks/ValidatingWebhookBuilder.cs index 88cf4ed4..4c04cdf1 100644 --- a/src/KubeOps/Operator/Webhooks/ValidatingWebhookBuilder.cs +++ b/src/KubeOps/Operator/Webhooks/ValidatingWebhookBuilder.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using k8s.Models; using KubeOps.KubernetesClient.Entities; using KubeOps.Operator.Builder; @@ -60,7 +60,7 @@ public List BuildWebhooks(WebhookConfig webhookConfig) var crd = entityType.ToEntityDefinition(); - return new V1ValidatingWebhook + var webhook = new V1ValidatingWebhook { Name = name.TrimWebhookName(), AdmissionReviewVersions = new[] { "v1" }, @@ -79,6 +79,13 @@ public List BuildWebhooks(WebhookConfig webhookConfig) }, ClientConfig = clientConfig, }; + + if (instance is IConfigurableValidationWebhook configurable) + { + configurable.Configure(webhook); + } + + return webhook; }) .ToList(); }