Skip to content

Commit b700a99

Browse files
committed
Move experimental API v1beta1 webhooks to separate package
1 parent 8b0e797 commit b700a99

File tree

8 files changed

+177
-70
lines changed

8 files changed

+177
-70
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ generate-manifests-core: $(CONTROLLER_GEN) $(KUSTOMIZE) ## Generate manifests e.
283283
paths=./internal/webhooks/... \
284284
paths=./$(EXP_DIR)/api/... \
285285
paths=./$(EXP_DIR)/internal/controllers/... \
286+
paths=./$(EXP_DIR)/internal/webhooks/... \
286287
paths=./$(EXP_DIR)/addons/api/... \
287288
paths=./$(EXP_DIR)/addons/internal/controllers/... \
288289
paths=./$(EXP_DIR)/ipam/api/... \

exp/internal/webhooks/doc.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
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 webhooks contains external webhook implementations for some of our API types.
18+
package webhooks

exp/api/v1beta1/machinepool_webhook.go renamed to exp/internal/webhooks/machinepool.go

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package v1beta1
17+
package webhooks
1818

1919
import (
20+
"context"
2021
"fmt"
2122
"strings"
2223

@@ -29,24 +30,35 @@ import (
2930
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
3031

3132
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
33+
expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
3234
"sigs.k8s.io/cluster-api/feature"
3335
"sigs.k8s.io/cluster-api/util/version"
3436
)
3537

36-
func (m *MachinePool) SetupWebhookWithManager(mgr ctrl.Manager) error {
38+
func (webhook *MachinePool) SetupWebhookWithManager(mgr ctrl.Manager) error {
3739
return ctrl.NewWebhookManagedBy(mgr).
38-
For(m).
40+
For(&expv1.MachinePool{}).
41+
WithDefaulter(webhook).
42+
WithValidator(webhook).
3943
Complete()
4044
}
4145

4246
// +kubebuilder:webhook:verbs=create;update,path=/validate-cluster-x-k8s-io-v1beta1-machinepool,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinepools,versions=v1beta1,name=validation.machinepool.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4347
// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1beta1-machinepool,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=machinepools,versions=v1beta1,name=default.machinepool.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
4448

45-
var _ webhook.Defaulter = &MachinePool{}
46-
var _ webhook.Validator = &MachinePool{}
49+
// MachinePool implements a validation and defaulting webhook for MachinePool.
50+
type MachinePool struct{}
51+
52+
var _ webhook.CustomValidator = &MachinePool{}
53+
var _ webhook.CustomDefaulter = &MachinePool{}
4754

4855
// Default implements webhook.Defaulter so a webhook will be registered for the type.
49-
func (m *MachinePool) Default() {
56+
func (webhook *MachinePool) Default(_ context.Context, obj runtime.Object) error {
57+
m, ok := obj.(*expv1.MachinePool)
58+
if !ok {
59+
return apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", obj))
60+
}
61+
5062
if m.Labels == nil {
5163
m.Labels = make(map[string]string)
5264
}
@@ -73,30 +85,45 @@ func (m *MachinePool) Default() {
7385
normalizedVersion := "v" + *m.Spec.Template.Spec.Version
7486
m.Spec.Template.Spec.Version = &normalizedVersion
7587
}
88+
return nil
7689
}
7790

7891
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
79-
func (m *MachinePool) ValidateCreate() (admission.Warnings, error) {
80-
return nil, m.validate(nil)
92+
func (webhook *MachinePool) ValidateCreate(_ context.Context, obj runtime.Object) (admission.Warnings, error) {
93+
mp, ok := obj.(*expv1.MachinePool)
94+
if !ok {
95+
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", obj))
96+
}
97+
98+
return nil, webhook.validate(nil, mp)
8199
}
82100

83101
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
84-
func (m *MachinePool) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
85-
oldMP, ok := old.(*MachinePool)
102+
func (webhook *MachinePool) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
103+
oldMP, ok := oldObj.(*expv1.MachinePool)
104+
if !ok {
105+
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", oldObj))
106+
}
107+
newMP, ok := newObj.(*expv1.MachinePool)
86108
if !ok {
87-
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", old))
109+
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", newObj))
88110
}
89-
return nil, m.validate(oldMP)
111+
return nil, webhook.validate(oldMP, newMP)
90112
}
91113

92114
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
93-
func (m *MachinePool) ValidateDelete() (admission.Warnings, error) {
94-
return nil, m.validate(nil)
115+
func (webhook *MachinePool) ValidateDelete(_ context.Context, obj runtime.Object) (admission.Warnings, error) {
116+
mp, ok := obj.(*expv1.MachinePool)
117+
if !ok {
118+
return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MachinePool but got a %T", obj))
119+
}
120+
121+
return nil, webhook.validate(nil, mp)
95122
}
96123

97-
func (m *MachinePool) validate(old *MachinePool) error {
124+
func (webhook *MachinePool) validate(oldObj, newObj *expv1.MachinePool) error {
98125
// NOTE: MachinePool is behind MachinePool feature gate flag; the web hook
99-
// must prevent creating new objects when the feature flag is disabled.
126+
// must prevent creating newObj objects when the feature flag is disabled.
100127
specPath := field.NewPath("spec")
101128
if !feature.Gates.Enabled(feature.MachinePool) {
102129
return field.Forbidden(
@@ -105,7 +132,7 @@ func (m *MachinePool) validate(old *MachinePool) error {
105132
)
106133
}
107134
var allErrs field.ErrorList
108-
if m.Spec.Template.Spec.Bootstrap.ConfigRef == nil && m.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
135+
if newObj.Spec.Template.Spec.Bootstrap.ConfigRef == nil && newObj.Spec.Template.Spec.Bootstrap.DataSecretName == nil {
109136
allErrs = append(
110137
allErrs,
111138
field.Required(
@@ -115,29 +142,29 @@ func (m *MachinePool) validate(old *MachinePool) error {
115142
)
116143
}
117144

118-
if m.Spec.Template.Spec.Bootstrap.ConfigRef != nil && m.Spec.Template.Spec.Bootstrap.ConfigRef.Namespace != m.Namespace {
145+
if newObj.Spec.Template.Spec.Bootstrap.ConfigRef != nil && newObj.Spec.Template.Spec.Bootstrap.ConfigRef.Namespace != newObj.Namespace {
119146
allErrs = append(
120147
allErrs,
121148
field.Invalid(
122149
specPath.Child("template", "spec", "bootstrap", "configRef", "namespace"),
123-
m.Spec.Template.Spec.Bootstrap.ConfigRef.Namespace,
150+
newObj.Spec.Template.Spec.Bootstrap.ConfigRef.Namespace,
124151
"must match metadata.namespace",
125152
),
126153
)
127154
}
128155

129-
if m.Spec.Template.Spec.InfrastructureRef.Namespace != m.Namespace {
156+
if newObj.Spec.Template.Spec.InfrastructureRef.Namespace != newObj.Namespace {
130157
allErrs = append(
131158
allErrs,
132159
field.Invalid(
133160
specPath.Child("infrastructureRef", "namespace"),
134-
m.Spec.Template.Spec.InfrastructureRef.Namespace,
161+
newObj.Spec.Template.Spec.InfrastructureRef.Namespace,
135162
"must match metadata.namespace",
136163
),
137164
)
138165
}
139166

140-
if old != nil && old.Spec.ClusterName != m.Spec.ClusterName {
167+
if oldObj != nil && oldObj.Spec.ClusterName != newObj.Spec.ClusterName {
141168
allErrs = append(
142169
allErrs,
143170
field.Forbidden(
@@ -146,17 +173,17 @@ func (m *MachinePool) validate(old *MachinePool) error {
146173
)
147174
}
148175

149-
if m.Spec.Template.Spec.Version != nil {
150-
if !version.KubeSemver.MatchString(*m.Spec.Template.Spec.Version) {
151-
allErrs = append(allErrs, field.Invalid(specPath.Child("template", "spec", "version"), *m.Spec.Template.Spec.Version, "must be a valid semantic version"))
176+
if newObj.Spec.Template.Spec.Version != nil {
177+
if !version.KubeSemver.MatchString(*newObj.Spec.Template.Spec.Version) {
178+
allErrs = append(allErrs, field.Invalid(specPath.Child("template", "spec", "version"), *newObj.Spec.Template.Spec.Version, "must be a valid semantic version"))
152179
}
153180
}
154181

155182
// Validate the metadata of the MachinePool template.
156-
allErrs = append(allErrs, m.Spec.Template.ObjectMeta.Validate(specPath.Child("template", "metadata"))...)
183+
allErrs = append(allErrs, newObj.Spec.Template.ObjectMeta.Validate(specPath.Child("template", "metadata"))...)
157184

158185
if len(allErrs) == 0 {
159186
return nil
160187
}
161-
return apierrors.NewInvalid(GroupVersion.WithKind("MachinePool").GroupKind(), m.Name, allErrs)
188+
return apierrors.NewInvalid(clusterv1.GroupVersion.WithKind("MachinePool").GroupKind(), newObj.Name, allErrs)
162189
}

0 commit comments

Comments
 (0)