@@ -18,12 +18,15 @@ limitations under the License.
18
18
package v1
19
19
20
20
import (
21
+ "context"
22
+ "fmt"
21
23
"github.com/robfig/cron"
22
24
apierrors "k8s.io/apimachinery/pkg/api/errors"
23
- "k8s.io/apimachinery/pkg/runtime"
24
25
"k8s.io/apimachinery/pkg/runtime/schema"
25
26
validationutils "k8s.io/apimachinery/pkg/util/validation"
26
27
"k8s.io/apimachinery/pkg/util/validation/field"
28
+
29
+ "k8s.io/apimachinery/pkg/runtime"
27
30
ctrl "sigs.k8s.io/controller-runtime"
28
31
logf "sigs.k8s.io/controller-runtime/pkg/log"
29
32
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -46,6 +49,13 @@ Then, we set up the webhook with the manager.
46
49
func (r * CronJob ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
47
50
return ctrl .NewWebhookManagedBy (mgr ).
48
51
For (r ).
52
+ WithValidator (& CronJobCustomValidator {}).
53
+ WithDefaulter (& CronJobCustomDefaulter {
54
+ DefaultConcurrencyPolicy : AllowConcurrent ,
55
+ DefaultSuspend : false ,
56
+ DefaultSuccessfulJobsHistoryLimit : 3 ,
57
+ DefaultFailedJobsHistoryLimit : 1 ,
58
+ }).
49
59
Complete ()
50
60
}
51
61
@@ -59,32 +69,53 @@ The meaning of each marker can be found [here](/reference/markers/webhook.md).
59
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
60
70
61
71
/*
62
- We use the `webhook.Defaulter ` interface to set defaults to our CRD.
72
+ We use the `webhook.CustomDefaulter ` interface to set defaults to our CRD.
63
73
A webhook will automatically be served that calls this defaulting.
64
74
65
75
The `Default` method is expected to mutate the receiver, setting the defaults.
66
76
*/
67
77
68
- var _ webhook.Defaulter = & CronJob {}
78
+ // +kubebuilder:object:generate=false
79
+ // CronJobCustomDefaulter struct is responsible for setting default values on the custom resource of the
80
+ // Kind CronJob when those are created or updated.
81
+ //
82
+ // NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
83
+ // as it is used only for temporary operations and does not need to be deeply copied.
84
+ type CronJobCustomDefaulter struct {
85
+
86
+ // Default values for various CronJob fields
87
+ DefaultConcurrencyPolicy ConcurrencyPolicy
88
+ DefaultSuspend bool
89
+ DefaultSuccessfulJobsHistoryLimit int32
90
+ DefaultFailedJobsHistoryLimit int32
91
+ }
69
92
70
- // Default implements webhook.Defaulter so a webhook will be registered for the type
71
- func (r * CronJob ) Default () {
72
- cronjoblog .Info ("default" , "name" , r .Name )
93
+ var _ webhook.CustomDefaulter = & CronJobCustomDefaulter {}
73
94
74
- if r .Spec .ConcurrencyPolicy == "" {
75
- r .Spec .ConcurrencyPolicy = AllowConcurrent
95
+ // Default implements webhook.CustomDefaulter so a webhook will be registered for the Kind CronJob
96
+ func (d * CronJobCustomDefaulter ) Default (ctx context.Context , obj runtime.Object ) error {
97
+ cronjob , ok := obj .(* CronJob )
98
+ if ! ok {
99
+ return fmt .Errorf ("expected an CronJob object but got %T" , obj )
76
100
}
77
- if r .Spec .Suspend == nil {
78
- r .Spec .Suspend = new (bool )
101
+ cronjoblog .Info ("Defaulting for CronJob" , "name" , cronjob .GetName ())
102
+
103
+ if cronjob .Spec .ConcurrencyPolicy == "" {
104
+ cronjob .Spec .ConcurrencyPolicy = AllowConcurrent
105
+ }
106
+ if cronjob .Spec .Suspend == nil {
107
+ cronjob .Spec .Suspend = new (bool )
79
108
}
80
- if r .Spec .SuccessfulJobsHistoryLimit == nil {
81
- r .Spec .SuccessfulJobsHistoryLimit = new (int32 )
82
- * r .Spec .SuccessfulJobsHistoryLimit = 3
109
+ if cronjob .Spec .SuccessfulJobsHistoryLimit == nil {
110
+ cronjob .Spec .SuccessfulJobsHistoryLimit = new (int32 )
111
+ * cronjob .Spec .SuccessfulJobsHistoryLimit = 3
83
112
}
84
- if r .Spec .FailedJobsHistoryLimit == nil {
85
- r .Spec .FailedJobsHistoryLimit = new (int32 )
86
- * r .Spec .FailedJobsHistoryLimit = 1
113
+ if cronjob .Spec .FailedJobsHistoryLimit == nil {
114
+ cronjob .Spec .FailedJobsHistoryLimit = new (int32 )
115
+ * cronjob .Spec .FailedJobsHistoryLimit = 1
87
116
}
117
+
118
+ return nil
88
119
}
89
120
90
121
/*
@@ -101,7 +132,7 @@ sometimes more advanced use cases call for complex validation.
101
132
For instance, we'll see below that we use this to validate a well-formed cron
102
133
schedule without making up a long regular expression.
103
134
104
- If `webhook.Validator ` interface is implemented, a webhook will automatically be
135
+ If `webhook.CustomValidator ` interface is implemented, a webhook will automatically be
105
136
served that calls the validation.
106
137
107
138
The `ValidateCreate`, `ValidateUpdate` and `ValidateDelete` methods are expected
@@ -118,27 +149,50 @@ validate anything on deletion.
118
149
// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
119
150
// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
120
151
121
- var _ webhook.Validator = & CronJob {}
152
+ // +kubebuilder:object:generate=false
153
+ // CronJobCustomValidator struct is responsible for validating the CronJob resource
154
+ // when it is created, updated, or deleted.
155
+ //
156
+ // NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
157
+ // as this struct is used only for temporary operations and does not need to be deeply copied.
158
+ type CronJobCustomValidator struct {
159
+ //TODO(user): Add more fields as needed for validation
160
+ }
161
+
162
+ var _ webhook.CustomValidator = & CronJobCustomValidator {}
122
163
123
- // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
124
- func (r * CronJob ) ValidateCreate () (admission.Warnings , error ) {
125
- cronjoblog .Info ("validate create" , "name" , r .Name )
164
+ // ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type CronJob
165
+ func (v * CronJobCustomValidator ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
166
+ cronjob , ok := obj .(* CronJob )
167
+ if ! ok {
168
+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
169
+ }
170
+ cronjoblog .Info ("Validation for CronJob upon creation" , "name" , cronjob .GetName ())
126
171
127
- return nil , r .validateCronJob ()
172
+ return nil , cronjob .validateCronJob ()
128
173
}
129
174
130
- // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
131
- func (r * CronJob ) ValidateUpdate (old runtime.Object ) (admission.Warnings , error ) {
132
- cronjoblog .Info ("validate update" , "name" , r .Name )
175
+ // ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type CronJob
176
+ func (v * CronJobCustomValidator ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
177
+ cronjob , ok := newObj .(* CronJob )
178
+ if ! ok {
179
+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , newObj )
180
+ }
181
+ cronjoblog .Info ("Validation for CronJob upon update" , "name" , cronjob .GetName ())
133
182
134
- return nil , r .validateCronJob ()
183
+ return nil , cronjob .validateCronJob ()
135
184
}
136
185
137
- // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
138
- func (r * CronJob ) ValidateDelete () (admission.Warnings , error ) {
139
- cronjoblog .Info ("validate delete" , "name" , r .Name )
186
+ // ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type CronJob
187
+ func (v * CronJobCustomValidator ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
188
+ cronjob , ok := obj .(* CronJob )
189
+ if ! ok {
190
+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
191
+ }
192
+ cronjoblog .Info ("Validation for CronJob upon deletion" , "name" , cronjob .GetName ())
140
193
141
194
// TODO(user): fill in your validation logic upon object deletion.
195
+
142
196
return nil , nil
143
197
}
144
198
@@ -204,13 +258,13 @@ the validation schema.
204
258
205
259
func (r * CronJob ) validateCronJobName () * field.Error {
206
260
if len (r .ObjectMeta .Name ) > validationutils .DNS1035LabelMaxLength - 11 {
207
- // The job name length is 63 character like all Kubernetes objects
261
+ // The job name length is 63 characters like all Kubernetes objects
208
262
// (which must fit in a DNS subdomain). The cronjob controller appends
209
263
// a 11-character suffix to the cronjob (`-$TIMESTAMP`) when creating
210
264
// a job. The job name length limit is 63 characters. Therefore cronjob
211
265
// names must have length <= 63-11=52. If we don't validate this here,
212
266
// then job creation will fail later.
213
- return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), r .Name , "must be no more than 52 characters" )
267
+ return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), r .ObjectMeta . Name , "must be no more than 52 characters" )
214
268
}
215
269
return nil
216
270
}
0 commit comments