Skip to content
This repository was archived by the owner on Oct 28, 2024. It is now read-only.

Commit 058f132

Browse files
authored
Merge pull request #194 from jichenjc/add_webhook
✨ Add webhook framework
2 parents d4de8a0 + c1d92df commit 058f132

9 files changed

+271
-40
lines changed

api/v1alpha4/nestedcluster_webhook.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2021 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 v1alpha4
18+
19+
import (
20+
"reflect"
21+
22+
"k8s.io/apimachinery/pkg/runtime"
23+
"k8s.io/apimachinery/pkg/util/validation/field"
24+
"sigs.k8s.io/controller-runtime/pkg/builder"
25+
"sigs.k8s.io/controller-runtime/pkg/manager"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook"
27+
)
28+
29+
// NestedclusterImmutableMsg ...
30+
const NestedclusterImmutableMsg = "Nestedclusters spec field is immutable. Please create a new resource instead. Ref doc: https://cluster-api.sigs.k8s.io/tasks/change-machine-template.html"
31+
32+
func (r *NestedCluster) SetupWebhookWithManager(mgr manager.Manager) error {
33+
return builder.WebhookManagedBy(mgr).
34+
For(r).
35+
Complete()
36+
}
37+
38+
// +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1alpha4-nestedcluster,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=nestedclusters,versions=v1alpha4,name=validation.nestedclusters.infrastructure.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1
39+
40+
var _ webhook.Validator = &NestedCluster{}
41+
42+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
43+
func (r *NestedCluster) ValidateCreate() error {
44+
return nil
45+
}
46+
47+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
48+
func (r *NestedCluster) ValidateUpdate(old runtime.Object) error {
49+
var allErrs field.ErrorList
50+
oldNestedcluster := old.(*NestedCluster)
51+
52+
if !reflect.DeepEqual(r.Spec, oldNestedcluster.Spec) {
53+
allErrs = append(allErrs,
54+
field.Invalid(field.NewPath("spec", "template", "spec"), r, NestedclusterImmutableMsg),
55+
)
56+
}
57+
58+
if len(allErrs) != 0 {
59+
return aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
60+
}
61+
62+
return nil
63+
}
64+
65+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
66+
func (r *NestedCluster) ValidateDelete() error {
67+
return nil
68+
}
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright 2021 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 v1alpha4
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/gomega"
23+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"
25+
)
26+
27+
func TestNestedCluster_ValidateUpdate(t *testing.T) {
28+
g := NewWithT(t)
29+
30+
tests := []struct {
31+
name string
32+
old *NestedCluster
33+
new *NestedCluster
34+
wantErr bool
35+
}{
36+
{
37+
name: "NestedCluster with immutable spec",
38+
old: &NestedCluster{
39+
Spec: NestedClusterSpec{
40+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
41+
Host: "foo",
42+
Port: 6443,
43+
},
44+
},
45+
},
46+
new: &NestedCluster{
47+
Spec: NestedClusterSpec{
48+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
49+
Host: "bar",
50+
Port: 6443,
51+
},
52+
},
53+
},
54+
wantErr: true,
55+
},
56+
{
57+
name: "NestedCluster with mutable metadata",
58+
old: &NestedCluster{
59+
Spec: NestedClusterSpec{
60+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
61+
Host: "foo",
62+
Port: 6443,
63+
},
64+
},
65+
ObjectMeta: metav1.ObjectMeta{
66+
Name: "foo",
67+
},
68+
},
69+
new: &NestedCluster{
70+
Spec: NestedClusterSpec{
71+
ControlPlaneEndpoint: clusterv1.APIEndpoint{
72+
Host: "foo",
73+
Port: 6443,
74+
},
75+
},
76+
ObjectMeta: metav1.ObjectMeta{
77+
Name: "fooNew",
78+
},
79+
},
80+
},
81+
}
82+
for _, tt := range tests {
83+
t.Run(tt.name, func(t *testing.T) {
84+
t.Parallel()
85+
err := tt.new.ValidateUpdate(tt.old)
86+
if tt.wantErr {
87+
g.Expect(err).To(HaveOccurred())
88+
} else {
89+
g.Expect(err).NotTo(HaveOccurred())
90+
}
91+
})
92+
}
93+
}

api/v1alpha4/webhooks.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright 2021 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 v1alpha4
18+
19+
import (
20+
apierrors "k8s.io/apimachinery/pkg/api/errors"
21+
"k8s.io/apimachinery/pkg/runtime/schema"
22+
"k8s.io/apimachinery/pkg/util/validation/field"
23+
)
24+
25+
func aggregateObjErrors(gk schema.GroupKind, name string, allErrs field.ErrorList) error {
26+
if len(allErrs) == 0 {
27+
return nil
28+
}
29+
30+
return apierrors.NewInvalid(
31+
gk,
32+
name,
33+
allErrs,
34+
)
35+
}

api/v1alpha4/zz_generated.deepcopy.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/default/kustomization.yaml

+30-30
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ bases:
1414
- ../manager
1515
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
1616
# crd/kustomization.yaml
17-
#- ../webhook
17+
- ../webhook
1818
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
19-
#- ../certmanager
19+
- ../certmanager
2020
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
2121
#- ../prometheus
2222

@@ -30,39 +30,39 @@ patchesStrategicMerge:
3030

3131
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
3232
# crd/kustomization.yaml
33-
#- manager_webhook_patch.yaml
33+
- manager_webhook_patch.yaml
3434

3535
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
3636
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
3737
# 'CERTMANAGER' needs to be enabled to use ca injection
38-
#- webhookcainjection_patch.yaml
38+
- webhookcainjection_patch.yaml
3939

4040
# the following config is for teaching kustomize how to do var substitution
4141
vars:
4242
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
43-
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
44-
# objref:
45-
# kind: Certificate
46-
# group: cert-manager.io
47-
# version: v1alpha2
48-
# name: serving-cert # this name should match the one in certificate.yaml
49-
# fieldref:
50-
# fieldpath: metadata.namespace
51-
#- name: CERTIFICATE_NAME
52-
# objref:
53-
# kind: Certificate
54-
# group: cert-manager.io
55-
# version: v1alpha2
56-
# name: serving-cert # this name should match the one in certificate.yaml
57-
#- name: SERVICE_NAMESPACE # namespace of the service
58-
# objref:
59-
# kind: Service
60-
# version: v1
61-
# name: webhook-service
62-
# fieldref:
63-
# fieldpath: metadata.namespace
64-
#- name: SERVICE_NAME
65-
# objref:
66-
# kind: Service
67-
# version: v1
68-
# name: webhook-service
43+
- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
44+
objref:
45+
kind: Certificate
46+
group: cert-manager.io
47+
version: v1alpha2
48+
name: serving-cert # this name should match the one in certificate.yaml
49+
fieldref:
50+
fieldpath: metadata.namespace
51+
- name: CERTIFICATE_NAME
52+
objref:
53+
kind: Certificate
54+
group: cert-manager.io
55+
version: v1alpha2
56+
name: serving-cert # this name should match the one in certificate.yaml
57+
- name: SERVICE_NAMESPACE # namespace of the service
58+
objref:
59+
kind: Service
60+
version: v1
61+
name: capn-webhook-service
62+
fieldref:
63+
fieldpath: metadata.namespace
64+
- name: SERVICE_NAME
65+
objref:
66+
kind: Service
67+
version: v1
68+
name: capn-webhook-service

config/default/webhookcainjection_patch.yaml

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# This patch add annotation to admission webhook config and
22
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
3-
apiVersion: admissionregistration.k8s.io/v1beta1
4-
kind: MutatingWebhookConfiguration
5-
metadata:
6-
name: mutating-webhook-configuration
7-
annotations:
8-
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
3+
#apiVersion: admissionregistration.k8s.io/v1beta1
4+
#kind: MutatingWebhookConfiguration
5+
#metadata:
6+
# name: mutating-webhook-configuration
7+
# annotations:
8+
# cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
99
---
10-
apiVersion: admissionregistration.k8s.io/v1beta1
10+
apiVersion: admissionregistration.k8s.io/v1
1111
kind: ValidatingWebhookConfiguration
1212
metadata:
1313
name: validating-webhook-configuration

config/webhook/manifests.yaml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
---
3+
apiVersion: admissionregistration.k8s.io/v1
4+
kind: ValidatingWebhookConfiguration
5+
metadata:
6+
creationTimestamp: null
7+
name: validating-webhook-configuration
8+
webhooks:
9+
- admissionReviewVersions:
10+
- v1beta1
11+
clientConfig:
12+
service:
13+
name: capn-capn-webhook-service
14+
namespace: capn-system
15+
path: /validate-infrastructure-cluster-x-k8s-io-v1alpha4-nestedcluster
16+
failurePolicy: Fail
17+
matchPolicy: Equivalent
18+
name: validation.nestedclusters.infrastructure.x-k8s.io
19+
rules:
20+
- apiGroups:
21+
- infrastructure.cluster.x-k8s.io
22+
apiVersions:
23+
- v1alpha4
24+
operations:
25+
- CREATE
26+
- UPDATE
27+
resources:
28+
- nestedclusters
29+
sideEffects: None

config/webhook/service.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
apiVersion: v1
33
kind: Service
44
metadata:
5-
name: webhook-service
6-
namespace: system
5+
name: capn-webhook-service
6+
namespace: capn-system
77
spec:
88
ports:
99
- port: 443

main.go

+6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ func main() {
153153
setupLog.Error(err, "unable to create controller", "controller", "NestedCluster")
154154
os.Exit(1)
155155
}
156+
157+
if err := (&infrastructurev1.NestedCluster{}).SetupWebhookWithManager(mgr); err != nil {
158+
setupLog.Error(err, "unable to create webhook", "webhook", "NestedCluster")
159+
os.Exit(1)
160+
}
161+
156162
// +kubebuilder:scaffold:builder
157163

158164
setupLog.Info("Starting manager", "version", version.Get().String())

0 commit comments

Comments
 (0)