Skip to content

Commit 2daf75c

Browse files
Set up defaulting webhook (kubernetes-sigs#51)
* begin webhook work * work on webhook integration test * webhook integration tests pass * add another int test case * fix yaml format * fix namespace bug * update readme to install cert-manager * use helper fn isIndexedJob in integration test * undo last commit * add more details about cert manager to readme
1 parent 833394d commit 2daf75c

23 files changed

+684
-42
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ vet: ## Run go vet against code.
8484

8585
.PHONY: test
8686
test: manifests generate fmt vet envtest ## Run tests.
87-
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./pkg/... -coverprofile cover.out
87+
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./pkg/... ./api/... -coverprofile cover.out
8888

8989
##@ Build
9090

PROJECT

+4
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ resources:
1717
kind: JobSet
1818
path: sigs.k8s.io/jobset/api/v1alpha1
1919
version: v1alpha1
20+
webhooks:
21+
defaulting: true
22+
validation: true
23+
webhookVersion: v1
2024
version: "3"

README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ JobSet: An API for managing a group of Jobs as a unit.
44

55
# Installation
66

7-
To install the CRD and deploy the controller on the cluster selected on your `~/.kubeconfig`, run the following commands:
7+
### Prerequisites
8+
[cert-manager](https://cert-manager.io/) is required to create certificates for the webhook. To install
9+
it on your cluster, run the following command:
10+
```
11+
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
12+
```
13+
See more details about [cert-manager installation](https://cert-manager.io/docs/installation/).
14+
15+
To install the JobSet CRD and deploy the controller on the cluster selected on your `~/.kubeconfig`, run the following commands:
816
```
917
git clone https://github.com/kubernetes-sigs/jobset.git
1018
cd jobset
19+
1120
IMAGE_REGISTRY=<registry>/<project> make image-push deploy
1221
```
1322

api/v1alpha1/jobset_webhook.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package v1alpha1
15+
16+
import (
17+
"k8s.io/apimachinery/pkg/runtime"
18+
ctrl "sigs.k8s.io/controller-runtime"
19+
"sigs.k8s.io/controller-runtime/pkg/webhook"
20+
21+
batchv1 "k8s.io/api/batch/v1"
22+
)
23+
24+
func (r *JobSet) SetupWebhookWithManager(mgr ctrl.Manager) error {
25+
return ctrl.NewWebhookManagedBy(mgr).
26+
For(r).
27+
Complete()
28+
}
29+
30+
//+kubebuilder:webhook:path=/mutate-batch-x-k8s-io-v1alpha1-jobset,mutating=true,failurePolicy=fail,sideEffects=None,groups=batch.x-k8s.io,resources=jobsets,verbs=create;update,versions=v1alpha1,name=mjobset.kb.io,admissionReviewVersions=v1
31+
32+
var _ webhook.Defaulter = &JobSet{}
33+
34+
// Default implements webhook.Defaulter so a webhook will be registered for the type
35+
func (r *JobSet) Default() {
36+
// Default job completion mode to indexed.
37+
for i, rjob := range r.Spec.Jobs {
38+
if rjob.Template.Spec.CompletionMode == nil {
39+
r.Spec.Jobs[i].Template.Spec.CompletionMode = completionModePtr(batchv1.IndexedCompletion)
40+
}
41+
}
42+
}
43+
44+
//+kubebuilder:webhook:path=/validate-batch-x-k8s-io-v1alpha1-jobset,mutating=false,failurePolicy=fail,sideEffects=None,groups=batch.x-k8s.io,resources=jobsets,verbs=create;update,versions=v1alpha1,name=vjobset.kb.io,admissionReviewVersions=v1
45+
46+
var _ webhook.Validator = &JobSet{}
47+
48+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
49+
func (r *JobSet) ValidateCreate() error {
50+
return nil
51+
}
52+
53+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
54+
func (r *JobSet) ValidateUpdate(old runtime.Object) error {
55+
return nil
56+
}
57+
58+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
59+
func (r *JobSet) ValidateDelete() error {
60+
return nil
61+
}
62+
63+
func completionModePtr(mode batchv1.CompletionMode) *batchv1.CompletionMode {
64+
return &mode
65+
}

api/v1alpha1/jobset_webhook_test.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package v1alpha1
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
batchv1 "k8s.io/api/batch/v1"
8+
)
9+
10+
func TestJobSetDefaulting(t *testing.T) {
11+
testCases := []struct {
12+
name string
13+
js *JobSet
14+
want *JobSet
15+
}{
16+
{
17+
name: "job completion mode is unset",
18+
js: &JobSet{
19+
Spec: JobSetSpec{
20+
Jobs: []ReplicatedJob{
21+
{
22+
Template: batchv1.JobTemplateSpec{
23+
Spec: batchv1.JobSpec{},
24+
},
25+
},
26+
},
27+
},
28+
},
29+
want: &JobSet{
30+
Spec: JobSetSpec{
31+
Jobs: []ReplicatedJob{
32+
{
33+
Template: batchv1.JobTemplateSpec{
34+
Spec: batchv1.JobSpec{
35+
CompletionMode: completionModePtr(batchv1.IndexedCompletion),
36+
},
37+
},
38+
},
39+
},
40+
},
41+
},
42+
},
43+
{
44+
name: "job completion mode is set to non-indexed",
45+
js: &JobSet{
46+
Spec: JobSetSpec{
47+
Jobs: []ReplicatedJob{
48+
{
49+
Template: batchv1.JobTemplateSpec{
50+
Spec: batchv1.JobSpec{
51+
CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
52+
},
53+
},
54+
},
55+
},
56+
},
57+
},
58+
want: &JobSet{
59+
Spec: JobSetSpec{
60+
Jobs: []ReplicatedJob{
61+
{
62+
Template: batchv1.JobTemplateSpec{
63+
Spec: batchv1.JobSpec{
64+
CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
65+
},
66+
},
67+
},
68+
},
69+
},
70+
},
71+
},
72+
}
73+
74+
for _, tc := range testCases {
75+
t.Run(tc.name, func(t *testing.T) {
76+
tc.js.Default()
77+
if diff := cmp.Diff(tc.want, tc.js); diff != "" {
78+
t.Errorf("unexpected jobset defaulting: (-want/+got): %s", diff)
79+
}
80+
})
81+
}
82+
}

api/v1alpha1/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/certmanager/certificate.yaml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# The following manifests contain a self-signed issuer CR and a certificate CR.
2+
# More document can be found at https://docs.cert-manager.io
3+
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4+
apiVersion: cert-manager.io/v1
5+
kind: Issuer
6+
metadata:
7+
labels:
8+
app.kubernetes.io/name: issuer
9+
app.kubernetes.io/instance: selfsigned-issuer
10+
app.kubernetes.io/component: certificate
11+
app.kubernetes.io/created-by: jobset
12+
app.kubernetes.io/part-of: jobset
13+
app.kubernetes.io/managed-by: kustomize
14+
name: selfsigned-issuer
15+
namespace: system
16+
spec:
17+
selfSigned: {}
18+
---
19+
apiVersion: cert-manager.io/v1
20+
kind: Certificate
21+
metadata:
22+
labels:
23+
app.kubernetes.io/name: certificate
24+
app.kubernetes.io/instance: serving-cert
25+
app.kubernetes.io/component: certificate
26+
app.kubernetes.io/created-by: jobset
27+
app.kubernetes.io/part-of: jobset
28+
app.kubernetes.io/managed-by: kustomize
29+
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
30+
namespace: system
31+
spec:
32+
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
33+
dnsNames:
34+
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
35+
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
36+
issuerRef:
37+
kind: Issuer
38+
name: selfsigned-issuer
39+
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize

config/certmanager/kustomization.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resources:
2+
- certificate.yaml
3+
4+
configurations:
5+
- kustomizeconfig.yaml
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This configuration is for teaching kustomize how to update name ref and var substitution
2+
nameReference:
3+
- kind: Issuer
4+
group: cert-manager.io
5+
fieldSpecs:
6+
- kind: Certificate
7+
group: cert-manager.io
8+
path: spec/issuerRef/name
9+
10+
varReference:
11+
- kind: Certificate
12+
group: cert-manager.io
13+
path: spec/commonName
14+
- kind: Certificate
15+
group: cert-manager.io
16+
path: spec/dnsNames

config/crd/kustomization.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ resources:
88
patchesStrategicMerge:
99
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
1010
# patches here are for enabling the conversion webhook for each CRD
11-
#- patches/webhook_in_jobsets.yaml
11+
- patches/webhook_in_jobsets.yaml
1212
#+kubebuilder:scaffold:crdkustomizewebhookpatch
1313

1414
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
1515
# patches here are for enabling the CA injection for each CRD
16-
#- patches/cainjection_in_jobsets.yaml
16+
- patches/cainjection_in_jobsets.yaml
1717
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
1818

1919
# the following config is for teaching kustomize how to do kustomization for CRDs.

config/default/kustomization.yaml

+30-30
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ bases:
1818
- ../manager
1919
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
2020
# crd/kustomization.yaml
21-
#- ../webhook
21+
- ../webhook
2222
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
23-
#- ../certmanager
23+
- ../certmanager
2424
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
2525
#- ../prometheus
2626

@@ -34,39 +34,39 @@ patchesStrategicMerge:
3434

3535
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
3636
# crd/kustomization.yaml
37-
#- manager_webhook_patch.yaml
37+
- manager_webhook_patch.yaml
3838

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

4444
# the following config is for teaching kustomize how to do var substitution
4545
vars:
4646
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
47-
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
48-
# objref:
49-
# kind: Certificate
50-
# group: cert-manager.io
51-
# version: v1
52-
# name: serving-cert # this name should match the one in certificate.yaml
53-
# fieldref:
54-
# fieldpath: metadata.namespace
55-
#- name: CERTIFICATE_NAME
56-
# objref:
57-
# kind: Certificate
58-
# group: cert-manager.io
59-
# version: v1
60-
# name: serving-cert # this name should match the one in certificate.yaml
61-
#- name: SERVICE_NAMESPACE # namespace of the service
62-
# objref:
63-
# kind: Service
64-
# version: v1
65-
# name: webhook-service
66-
# fieldref:
67-
# fieldpath: metadata.namespace
68-
#- name: SERVICE_NAME
69-
# objref:
70-
# kind: Service
71-
# version: v1
72-
# name: webhook-service
47+
- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
48+
objref:
49+
kind: Certificate
50+
group: cert-manager.io
51+
version: v1
52+
name: serving-cert # this name should match the one in certificate.yaml
53+
fieldref:
54+
fieldpath: metadata.namespace
55+
- name: CERTIFICATE_NAME
56+
objref:
57+
kind: Certificate
58+
group: cert-manager.io
59+
version: v1
60+
name: serving-cert # this name should match the one in certificate.yaml
61+
- name: SERVICE_NAMESPACE # namespace of the service
62+
objref:
63+
kind: Service
64+
version: v1
65+
name: webhook-service
66+
fieldref:
67+
fieldpath: metadata.namespace
68+
- name: SERVICE_NAME
69+
objref:
70+
kind: Service
71+
version: v1
72+
name: webhook-service
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: controller-manager
5+
namespace: system
6+
spec:
7+
template:
8+
spec:
9+
containers:
10+
- name: manager
11+
ports:
12+
- containerPort: 9443
13+
name: webhook-server
14+
protocol: TCP
15+
volumeMounts:
16+
- mountPath: /tmp/k8s-webhook-server/serving-certs
17+
name: cert
18+
readOnly: true
19+
volumes:
20+
- name: cert
21+
secret:
22+
defaultMode: 420
23+
secretName: webhook-server-cert

0 commit comments

Comments
 (0)