Skip to content

Commit

Permalink
feat: enable webhooks in sidero-controller-manager
Browse files Browse the repository at this point in the history
Based on #794, but instead of
using a dedicated controller for all webhooks keep all of them in each
own controller.

Additionally, implement validation webhooks for `Server` resource, which
validates that `bootFromDiskMethod` and `configPatches` are using proper
values.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
  • Loading branch information
Unix4ever committed Apr 8, 2022
1 parent 37a1d52 commit 511ddfc
Show file tree
Hide file tree
Showing 24 changed files with 313 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-configuration
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
---
apiVersion: admissionregistration.k8s.io/v1beta1
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
Expand Down
26 changes: 16 additions & 10 deletions app/caps-controller-manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ func main() {
os.Exit(1)
}

// +kubebuilder:scaffold:builder

setupWebhooks(mgr)
setupChecks(mgr)

setupLog.Info("starting manager")

if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}

func setupWebhooks(mgr ctrl.Manager) {
var err error

if err = (&infrav1alpha3.MetalCluster{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "MetalCluster")
os.Exit(1)
Expand All @@ -163,16 +179,6 @@ func main() {
setupLog.Error(err, "unable to create webhook", "webhook", "ServerBinding")
os.Exit(1)
}
// +kubebuilder:scaffold:builder

setupChecks(mgr)

setupLog.Info("starting manager")

if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}

func setupChecks(mgr ctrl.Manager) {
Expand Down
15 changes: 15 additions & 0 deletions app/sidero-controller-manager/api/v1alpha1/environment_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package v1alpha1

import (
ctrl "sigs.k8s.io/controller-runtime"
)

func (r *Environment) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}
112 changes: 112 additions & 0 deletions app/sidero-controller-manager/api/v1alpha1/server_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package v1alpha1

import (
"fmt"
"sort"

apierrors "k8s.io/apimachinery/pkg/api/errors"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"

siderotypes "github.com/talos-systems/sidero/app/sidero-controller-manager/pkg/types"
)

var operations = map[string]struct{}{
"add": {},
"remove": {},
"replace": {},
"copy": {},
"move": {},
"test": {},
}

var operationKinds = []string{}

func (r *Server) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}

//+kubebuilder:webhook:verbs=create;update;delete,path=/validate-metal-sidero-dev-v1alpha1-server,mutating=false,failurePolicy=fail,groups=metal.sidero.dev,resources=servers,versions=v1alpha1,name=vservers.metal.sidero.dev,sideEffects=None,admissionReviewVersions=v1

var _ webhook.Validator = &Server{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (r *Server) ValidateCreate() error {
return r.validate()
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (r *Server) ValidateUpdate(old runtime.Object) error {
return r.validate()
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
func (r *Server) ValidateDelete() error {
return nil
}

func (r *Server) validate() error {
var allErrs field.ErrorList

validValues := []siderotypes.BootFromDisk{
"",
siderotypes.BootIPXEExit,
siderotypes.Boot404,
siderotypes.BootSANDisk,
}

var valid bool

for _, v := range validValues {
if r.Spec.BootFromDiskMethod == v {
valid = true

break
}
}

if !valid {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec").Child("bootFromDiskMethod"), r.Spec.BootFromDiskMethod,
fmt.Sprintf("valid values are: %q", validValues),
),
)
}

for index, patch := range r.Spec.ConfigPatches {
if _, ok := operations[patch.Op]; !ok {
allErrs = append(allErrs,
field.Invalid(field.NewPath("spec").Child("configPatches").Child(fmt.Sprintf("%d", index)).Child("op"), patch.Op,
fmt.Sprintf("valid values are: %q", operationKinds),
),
)
}
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(
schema.GroupKind{Group: GroupVersion.Group, Kind: "Server"},
r.Name, allErrs)
}

func init() {
operationKinds = make([]string, 0, len(operations))

for key := range operations {
operationKinds = append(operationKinds, key)
}

sort.Strings(operationKinds)
}
15 changes: 15 additions & 0 deletions app/sidero-controller-manager/api/v1alpha1/serverclass_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package v1alpha1

import (
ctrl "sigs.k8s.io/controller-runtime"
)

func (r *ServerClass) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ metadata:
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
namespace: system
spec:
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
# $(SIDERO_SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
dnsNames:
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
- $(SIDERO_SERVICE_NAME).$(SERVICE_NAMESPACE).svc
- $(SIDERO_SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
issuerRef:
kind: Issuer
name: selfsigned-issuer
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
secretName: $(SIDERO_SERVICE_NAME)-cert # this secret will not be prefixed, since it's not managed by kustomize
12 changes: 6 additions & 6 deletions app/sidero-controller-manager/config/crd/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ commonLabels:
patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_environments.yaml
#- patches/webhook_in_servers.yaml
#- patches/webhook_in_serverclasses.yaml
- patches/webhook_in_environments.yaml
- patches/webhook_in_servers.yaml
- patches/webhook_in_serverclasses.yaml
# +kubebuilder:scaffold:crdkustomizewebhookpatch

# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD
#- patches/cainjection_in_environments.yaml
#- patches/cainjection_in_servers.yaml
#- patches/cainjection_in_serverclasses.yaml
- patches/cainjection_in_environments.yaml
- patches/cainjection_in_servers.yaml
- patches/cainjection_in_serverclasses.yaml
# +kubebuilder:scaffold:crdkustomizecainjectionpatch

# the following config is for teaching kustomize how to do kustomization for CRDs.
Expand Down
4 changes: 2 additions & 2 deletions app/sidero-controller-manager/config/crd/kustomizeconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ nameReference:
fieldSpecs:
- kind: CustomResourceDefinition
group: apiextensions.k8s.io
path: spec/conversion/webhookClientConfig/service/name
path: spec/conversion/webhook/clientConfig/service/name

namespace:
- kind: CustomResourceDefinition
group: apiextensions.k8s.io
path: spec/conversion/webhookClientConfig/service/namespace
path: spec/conversion/webhook/clientConfig/service/namespace
create: false

varReference:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(SIDERO_CERTIFICATE_NAME)
name: environments.metal.sidero.dev
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(SIDERO_CERTIFICATE_NAME)
name: serverclasses.metal.sidero.dev
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(SIDERO_CERTIFICATE_NAME)
name: servers.metal.sidero.dev
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: environments.metal.sidero.dev
spec:
conversion:
strategy: Webhook
webhookClientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
webhook:
conversionReviewVersions: ["v1", "v1beta1"]
clientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: serverclasses.metal.sidero.dev
spec:
conversion:
strategy: Webhook
webhookClientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
webhook:
conversionReviewVersions: ["v1", "v1beta1"]
clientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# The following patch enables conversion webhook for CRD
# CRD conversion requires k8s 1.13 or later.
apiVersion: apiextensions.k8s.io/v1beta1
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servers.metal.sidero.dev
spec:
conversion:
strategy: Webhook
webhookClientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
webhook:
conversionReviewVersions: ["v1", "v1beta1"]
clientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
caBundle: Cg==
service:
namespace: system
name: webhook-service
path: /convert
Loading

0 comments on commit 511ddfc

Please sign in to comment.