Skip to content

Commit b55ea5d

Browse files
authored
New feature: enable validation webhooks (#348)
- Scaffolding using the operator-sdk - Adapted the code just enabling Validation webhooks for Create and Update verbs. - Implement custom logic that validates the module's specs. Signed-off-by: Erusso7 <[email protected]>
1 parent 9e4c576 commit b55ea5d

17 files changed

+709
-42
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ help: ## Display this help.
9797

9898
.PHONY: manifests
9999
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
100-
$(CONTROLLER_GEN) crd paths="./api/..." output:crd:artifacts:config=config/crd/bases
100+
$(CONTROLLER_GEN) crd webhook paths="./api/..." output:crd:artifacts:config=config/crd/bases
101101
$(CONTROLLER_GEN) rbac:roleName=manager-role paths="./controllers" output:rbac:artifacts:config=config/rbac
102102

103103
# Hub
104-
$(CONTROLLER_GEN) crd paths="./api-hub/..." output:crd:artifacts:config=config/crd-hub/bases
104+
$(CONTROLLER_GEN) crd webhook paths="./api-hub/..." output:crd:artifacts:config=config/crd-hub/bases
105105
$(CONTROLLER_GEN) rbac:roleName=manager-role paths="./controllers/hub" output:rbac:artifacts:config=config/rbac-hub
106106

107107
.PHONY: generate

PROJECT

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ resources:
1616
kind: Module
1717
path: github.com/kubernetes-sigs/kernel-module-management/api/v1beta1
1818
version: v1beta1
19+
webhooks:
20+
validation: true
21+
webhookVersion: v1
1922
- api:
2023
crdVersion: v1
2124
namespaced: false

api/v1beta1/module_webhook.go

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
Copyright 2022.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
"k8s.io/apimachinery/pkg/runtime"
23+
"regexp"
24+
ctrl "sigs.k8s.io/controller-runtime"
25+
logf "sigs.k8s.io/controller-runtime/pkg/log"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook"
27+
)
28+
29+
// log is for logging in this package.
30+
var modulelog = logf.Log.WithName("module-resource")
31+
32+
func (m *Module) SetupWebhookWithManager(mgr ctrl.Manager) error {
33+
return ctrl.NewWebhookManagedBy(mgr).
34+
For(m).
35+
Complete()
36+
}
37+
38+
//+kubebuilder:webhook:path=/validate-kmm-sigs-x-k8s-io-v1beta1-module,mutating=false,failurePolicy=fail,sideEffects=None,groups=kmm.sigs.x-k8s.io,resources=modules,verbs=create;update,versions=v1beta1,name=vmodule.kb.io,admissionReviewVersions=v1
39+
40+
var _ webhook.Validator = &Module{}
41+
42+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
43+
func (m *Module) ValidateCreate() error {
44+
modulelog.Info("Validating Module creation", "name", m.Name, "namespace", m.Namespace)
45+
46+
if err := m.validateKernelMapping(); err != nil {
47+
return fmt.Errorf("failed to validate kernel mappings: %v", err)
48+
}
49+
50+
return m.validateModprobe()
51+
}
52+
53+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
54+
func (m *Module) ValidateUpdate(_ runtime.Object) error {
55+
modulelog.Info("Validating Module update", "name", m.Name, "namespace", m.Namespace)
56+
57+
if err := m.validateKernelMapping(); err != nil {
58+
return fmt.Errorf("failed to validate kernel mappings: %v", err)
59+
}
60+
61+
return m.validateModprobe()
62+
}
63+
64+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
65+
func (m *Module) ValidateDelete() error {
66+
return nil
67+
}
68+
69+
func (m *Module) validateKernelMapping() error {
70+
container := m.Spec.ModuleLoader.Container
71+
72+
for idx, km := range container.KernelMappings {
73+
if km.Regexp != "" && km.Literal != "" {
74+
return fmt.Errorf("regexp and literal are mutually exclusive properties at kernelMappings[%d]", idx)
75+
}
76+
77+
if km.Regexp == "" && km.Literal == "" {
78+
return fmt.Errorf("regexp or literal must be set at kernelMappings[%d]", idx)
79+
}
80+
81+
if _, err := regexp.Compile(km.Regexp); err != nil {
82+
return fmt.Errorf("invalid regexp at index %d: %v", idx, err)
83+
}
84+
85+
if container.ContainerImage == "" && km.ContainerImage == "" {
86+
return fmt.Errorf("missing spec.moduleLoader.container.kernelMappings[%d].containerImage", idx)
87+
}
88+
}
89+
90+
return nil
91+
}
92+
93+
func (m *Module) validateModprobe() error {
94+
modprobe := m.Spec.ModuleLoader.Container.Modprobe
95+
moduleNameDefined := modprobe.ModuleName != ""
96+
rawLoadArgsDefined := modprobe.RawArgs != nil && len(modprobe.RawArgs.Load) > 0
97+
rawUnloadArgsDefined := modprobe.RawArgs != nil && len(modprobe.RawArgs.Unload) > 0
98+
99+
if moduleNameDefined {
100+
if rawLoadArgsDefined || rawUnloadArgsDefined {
101+
return errors.New("rawArgs cannot be set when moduleName is set")
102+
}
103+
return nil
104+
}
105+
106+
if !rawLoadArgsDefined || !rawUnloadArgsDefined {
107+
return errors.New("load and unload rawArgs must be set when moduleName is unset")
108+
}
109+
110+
return nil
111+
}

0 commit comments

Comments
 (0)