@@ -31,6 +31,8 @@ import (
31
31
logf "sigs.k8s.io/controller-runtime/pkg/log"
32
32
"sigs.k8s.io/controller-runtime/pkg/webhook"
33
33
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
34
+
35
+ batchv1 "tutorial.kubebuilder.io/project/api/v1"
34
36
)
35
37
36
38
// +kubebuilder:docs-gen:collapse=Go imports
@@ -45,13 +47,12 @@ var cronjoblog = logf.Log.WithName("cronjob-resource")
45
47
Then, we set up the webhook with the manager.
46
48
*/
47
49
48
- // SetupWebhookWithManager will setup the manager to manage the webhooks.
49
- func (r * CronJob ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
50
- return ctrl .NewWebhookManagedBy (mgr ).
51
- For (r ).
50
+ // SetupCronJobWebhookWithManager registers the webhook for CronJob in the manager.
51
+ func SetupCronJobWebhookWithManager (mgr ctrl.Manager ) error {
52
+ return ctrl .NewWebhookManagedBy (mgr ).For (& batchv1.CronJob {}).
52
53
WithValidator (& CronJobCustomValidator {}).
53
54
WithDefaulter (& CronJobCustomDefaulter {
54
- DefaultConcurrencyPolicy : AllowConcurrent ,
55
+ DefaultConcurrencyPolicy : batchv1 . AllowConcurrent ,
55
56
DefaultSuspend : false ,
56
57
DefaultSuccessfulJobsHistoryLimit : 3 ,
57
58
DefaultFailedJobsHistoryLimit : 1 ,
@@ -66,7 +67,7 @@ This marker is responsible for generating a mutating webhook manifest.
66
67
The meaning of each marker can be found [here](/reference/markers/webhook.md).
67
68
*/
68
69
69
- // +kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob.kb.io,sideEffects=None,admissionReviewVersions=v1
70
+ // +kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob-v1 .kb.io,sideEffects=None,admissionReviewVersions=v1
70
71
71
72
/*
72
73
We use the `webhook.CustomDefaulter` interface to set defaults to our CRD.
@@ -86,7 +87,7 @@ The `Default` method is expected to mutate the receiver, setting the defaults.
86
87
type CronJobCustomDefaulter struct {
87
88
88
89
// Default values for various CronJob fields
89
- DefaultConcurrencyPolicy ConcurrencyPolicy
90
+ DefaultConcurrencyPolicy batchv1. ConcurrencyPolicy
90
91
DefaultSuspend bool
91
92
DefaultSuccessfulJobsHistoryLimit int32
92
93
DefaultFailedJobsHistoryLimit int32
@@ -96,40 +97,42 @@ var _ webhook.CustomDefaulter = &CronJobCustomDefaulter{}
96
97
97
98
// Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind CronJob.
98
99
func (d * CronJobCustomDefaulter ) Default (ctx context.Context , obj runtime.Object ) error {
99
- cronjob , ok := obj .(* CronJob )
100
+ cronjob , ok := obj .(* batchv1.CronJob )
101
+
100
102
if ! ok {
101
103
return fmt .Errorf ("expected an CronJob object but got %T" , obj )
102
104
}
103
105
cronjoblog .Info ("Defaulting for CronJob" , "name" , cronjob .GetName ())
104
106
105
107
// Set default values
106
- cronjob .Default ()
107
-
108
+ d .applyDefaults (cronjob )
108
109
return nil
109
110
}
110
111
111
- func (r * CronJob ) Default () {
112
- if r .Spec .ConcurrencyPolicy == "" {
113
- r .Spec .ConcurrencyPolicy = AllowConcurrent
112
+ // applyDefaults applies default values to CronJob fields.
113
+ func (d * CronJobCustomDefaulter ) applyDefaults (cronJob * batchv1.CronJob ) {
114
+ if cronJob .Spec .ConcurrencyPolicy == "" {
115
+ cronJob .Spec .ConcurrencyPolicy = d .DefaultConcurrencyPolicy
114
116
}
115
- if r .Spec .Suspend == nil {
116
- r .Spec .Suspend = new (bool )
117
+ if cronJob .Spec .Suspend == nil {
118
+ cronJob .Spec .Suspend = new (bool )
119
+ * cronJob .Spec .Suspend = d .DefaultSuspend
117
120
}
118
- if r .Spec .SuccessfulJobsHistoryLimit == nil {
119
- r .Spec .SuccessfulJobsHistoryLimit = new (int32 )
120
- * r .Spec .SuccessfulJobsHistoryLimit = 3
121
+ if cronJob .Spec .SuccessfulJobsHistoryLimit == nil {
122
+ cronJob .Spec .SuccessfulJobsHistoryLimit = new (int32 )
123
+ * cronJob .Spec .SuccessfulJobsHistoryLimit = d . DefaultSuccessfulJobsHistoryLimit
121
124
}
122
- if r .Spec .FailedJobsHistoryLimit == nil {
123
- r .Spec .FailedJobsHistoryLimit = new (int32 )
124
- * r .Spec .FailedJobsHistoryLimit = 1
125
+ if cronJob .Spec .FailedJobsHistoryLimit == nil {
126
+ cronJob .Spec .FailedJobsHistoryLimit = new (int32 )
127
+ * cronJob .Spec .FailedJobsHistoryLimit = d . DefaultFailedJobsHistoryLimit
125
128
}
126
129
}
127
130
128
131
/*
129
132
This marker is responsible for generating a validating webhook manifest.
130
133
*/
131
134
132
- // +kubebuilder:webhook:verbs=create;update;delete,path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,versions=v1,name=vcronjob.kb.io,sideEffects=None,admissionReviewVersions=v1
135
+ // +kubebuilder:webhook:verbs=create;update;delete,path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,versions=v1,name=vcronjob-v1 .kb.io,sideEffects=None,admissionReviewVersions=v1
133
136
134
137
/*
135
138
We can validate our CRD beyond what's possible with declarative
@@ -171,29 +174,29 @@ var _ webhook.CustomValidator = &CronJobCustomValidator{}
171
174
172
175
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type CronJob.
173
176
func (v * CronJobCustomValidator ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
174
- cronjob , ok := obj .(* CronJob )
177
+ cronjob , ok := obj .(* batchv1. CronJob )
175
178
if ! ok {
176
179
return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
177
180
}
178
181
cronjoblog .Info ("Validation for CronJob upon creation" , "name" , cronjob .GetName ())
179
182
180
- return nil , cronjob . validateCronJob ()
183
+ return nil , validateCronJob (cronjob )
181
184
}
182
185
183
186
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type CronJob.
184
187
func (v * CronJobCustomValidator ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
185
- cronjob , ok := newObj .(* CronJob )
188
+ cronjob , ok := newObj .(* batchv1. CronJob )
186
189
if ! ok {
187
- return nil , fmt .Errorf ("expected a CronJob object but got %T" , newObj )
190
+ return nil , fmt .Errorf ("expected a CronJob object for the newObj but got got %T" , newObj )
188
191
}
189
192
cronjoblog .Info ("Validation for CronJob upon update" , "name" , cronjob .GetName ())
190
193
191
- return nil , cronjob . validateCronJob ()
194
+ return nil , validateCronJob (cronjob )
192
195
}
193
196
194
197
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type CronJob.
195
198
func (v * CronJobCustomValidator ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
196
- cronjob , ok := obj .(* CronJob )
199
+ cronjob , ok := obj .(* batchv1. CronJob )
197
200
if ! ok {
198
201
return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
199
202
}
@@ -208,21 +211,19 @@ func (v *CronJobCustomValidator) ValidateDelete(ctx context.Context, obj runtime
208
211
We validate the name and the spec of the CronJob.
209
212
*/
210
213
211
- func (r * CronJob ) validateCronJob () error {
214
+ // validateCronJob validates the fields of a CronJob object.
215
+ func validateCronJob (cronjob * batchv1.CronJob ) error {
212
216
var allErrs field.ErrorList
213
- if err := r . validateCronJobName (); err != nil {
217
+ if err := validateCronJobName (cronjob ); err != nil {
214
218
allErrs = append (allErrs , err )
215
219
}
216
- if err := r . validateCronJobSpec (); err != nil {
220
+ if err := validateCronJobSpec (cronjob ); err != nil {
217
221
allErrs = append (allErrs , err )
218
222
}
219
223
if len (allErrs ) == 0 {
220
224
return nil
221
225
}
222
-
223
- return apierrors .NewInvalid (
224
- schema.GroupKind {Group : "batch.tutorial.kubebuilder.io" , Kind : "CronJob" },
225
- r .Name , allErrs )
226
+ return apierrors .NewInvalid (schema.GroupKind {Group : "batch.tutorial.kubebuilder.io" , Kind : "CronJob" }, cronjob .Name , allErrs )
226
227
}
227
228
228
229
/*
@@ -235,19 +236,17 @@ declaring validation by running `controller-gen crd -w`,
235
236
or [here](/reference/markers/crd-validation.md).
236
237
*/
237
238
238
- func (r * CronJob ) validateCronJobSpec () * field.Error {
239
- // The field helpers from the kubernetes API machinery help us return nicely
240
- // structured validation errors.
241
- return validateScheduleFormat (
242
- r .Spec .Schedule ,
243
- field .NewPath ("spec" ).Child ("schedule" ))
239
+ // validateCronJobSpec validates the schedule field of the CronJob spec.
240
+ func validateCronJobSpec (cronjob * batchv1.CronJob ) * field.Error {
241
+ return validateScheduleFormat (cronjob .Spec .Schedule , field .NewPath ("spec" ).Child ("schedule" ))
244
242
}
245
243
246
244
/*
247
245
We'll need to validate the [cron](https://en.wikipedia.org/wiki/Cron) schedule
248
246
is well-formatted.
249
247
*/
250
248
249
+ // validateScheduleFormat validates that the schedule field follows the cron format.
251
250
func validateScheduleFormat (schedule string , fldPath * field.Path ) * field.Error {
252
251
if _ , err := cron .ParseStandard (schedule ); err != nil {
253
252
return field .Invalid (fldPath , schedule , err .Error ())
@@ -264,15 +263,10 @@ the apimachinery repo, so we can't declaratively validate it using
264
263
the validation schema.
265
264
*/
266
265
267
- func (r * CronJob ) validateCronJobName () * field.Error {
268
- if len (r .ObjectMeta .Name ) > validationutils .DNS1035LabelMaxLength - 11 {
269
- // The job name length is 63 characters like all Kubernetes objects
270
- // (which must fit in a DNS subdomain). The cronjob controller appends
271
- // a 11-character suffix to the cronjob (`-$TIMESTAMP`) when creating
272
- // a job. The job name length limit is 63 characters. Therefore cronjob
273
- // names must have length <= 63-11=52. If we don't validate this here,
274
- // then job creation will fail later.
275
- return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), r .ObjectMeta .Name , "must be no more than 52 characters" )
266
+ // validateCronJobName validates the name of the CronJob object.
267
+ func validateCronJobName (cronjob * batchv1.CronJob ) * field.Error {
268
+ if len (cronjob .ObjectMeta .Name ) > validationutils .DNS1035LabelMaxLength - 11 {
269
+ return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), cronjob .ObjectMeta .Name , "must be no more than 52 characters" )
276
270
}
277
271
return nil
278
272
}
0 commit comments