@@ -18,12 +18,15 @@ limitations under the License.
1818package v1
1919
2020import (
21+ "context"
22+ "fmt"
2123 "github.com/robfig/cron"
2224 apierrors "k8s.io/apimachinery/pkg/api/errors"
23- "k8s.io/apimachinery/pkg/runtime"
2425 "k8s.io/apimachinery/pkg/runtime/schema"
2526 validationutils "k8s.io/apimachinery/pkg/util/validation"
2627 "k8s.io/apimachinery/pkg/util/validation/field"
28+
29+ "k8s.io/apimachinery/pkg/runtime"
2730 ctrl "sigs.k8s.io/controller-runtime"
2831 logf "sigs.k8s.io/controller-runtime/pkg/log"
2932 "sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -46,6 +49,8 @@ Then, we set up the webhook with the manager.
4649func (r * CronJob ) SetupWebhookWithManager (mgr ctrl.Manager ) error {
4750 return ctrl .NewWebhookManagedBy (mgr ).
4851 For (r ).
52+ WithValidator (& CronJobCustomValidator {}).
53+ WithDefaulter (& CronJobCustomDefaulter {}).
4954 Complete ()
5055}
5156
@@ -65,26 +70,42 @@ A webhook will automatically be served that calls this defaulting.
6570The `Default` method is expected to mutate the receiver, setting the defaults.
6671*/
6772
68- var _ webhook. Defaulter = & CronJob {}
73+ type CronJobCustomDefaulter struct {}
6974
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 )
75+ var _ webhook.CustomDefaulter = & CronJobCustomDefaulter {}
7376
74- if r .Spec .ConcurrencyPolicy == "" {
75- r .Spec .ConcurrencyPolicy = AllowConcurrent
77+ // Default implements webhook.CustomDefaulter so a webhook will be registered for the type
78+ func (d * CronJobCustomDefaulter ) Default (ctx context.Context , obj runtime.Object ) error {
79+ cronjoblog .Info ("CustomDefaulter for Admiral" )
80+ req , err := admission .RequestFromContext (ctx )
81+ if err != nil {
82+ return fmt .Errorf ("expected admission.Request in ctx: %w" , err )
7683 }
77- if r .Spec .Suspend == nil {
78- r .Spec .Suspend = new (bool )
84+ if req .Kind .Kind != "CronJob" {
85+ return fmt .Errorf ("expected Kind Admiral got %q" , req .Kind .Kind )
86+ }
87+ castedObj , ok := obj .(* CronJob )
88+ if ! ok {
89+ return fmt .Errorf ("expected an CronJob object but got %T" , obj )
90+ }
91+ cronjoblog .Info ("default" , "name" , castedObj .GetName ())
92+
93+ if castedObj .Spec .ConcurrencyPolicy == "" {
94+ castedObj .Spec .ConcurrencyPolicy = AllowConcurrent
7995 }
80- if r .Spec .SuccessfulJobsHistoryLimit == nil {
81- r .Spec .SuccessfulJobsHistoryLimit = new (int32 )
82- * r .Spec .SuccessfulJobsHistoryLimit = 3
96+ if castedObj .Spec .Suspend == nil {
97+ castedObj .Spec .Suspend = new (bool )
8398 }
84- if r .Spec .FailedJobsHistoryLimit == nil {
85- r .Spec .FailedJobsHistoryLimit = new (int32 )
86- * r .Spec .FailedJobsHistoryLimit = 1
99+ if castedObj .Spec .SuccessfulJobsHistoryLimit == nil {
100+ castedObj .Spec .SuccessfulJobsHistoryLimit = new (int32 )
101+ * castedObj .Spec .SuccessfulJobsHistoryLimit = 3
87102 }
103+ if castedObj .Spec .FailedJobsHistoryLimit == nil {
104+ castedObj .Spec .FailedJobsHistoryLimit = new (int32 )
105+ * castedObj .Spec .FailedJobsHistoryLimit = 1
106+ }
107+
108+ return nil
88109}
89110
90111/*
@@ -118,40 +139,80 @@ validate anything on deletion.
118139// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
119140// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
120141
121- var _ webhook. Validator = & CronJob {}
142+ type CronJobCustomValidator struct {}
122143
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 )
144+ var _ webhook.CustomValidator = & CronJobCustomValidator {}
126145
127- return nil , r .validateCronJob ()
146+ // ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type
147+ func (v * CronJobCustomValidator ) ValidateCreate (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
148+ cronjoblog .Info ("Creation Validation for CronJob" )
149+
150+ req , err := admission .RequestFromContext (ctx )
151+ if err != nil {
152+ return nil , fmt .Errorf ("expected admission.Request in ctx: %w" , err )
153+ }
154+ if req .Kind .Kind != "CronJob" {
155+ return nil , fmt .Errorf ("expected Kind CronJob got %q" , req .Kind .Kind )
156+ }
157+ castedObj , ok := obj .(* CronJob )
158+ if ! ok {
159+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
160+ }
161+ cronjoblog .Info ("default" , "name" , castedObj .GetName ())
162+
163+ return nil , v .validateCronJob (castedObj )
128164}
129165
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 )
166+ // ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type
167+ func (v * CronJobCustomValidator ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
168+ cronjoblog .Info ("Update Validation for CronJob" )
169+ req , err := admission .RequestFromContext (ctx )
170+ if err != nil {
171+ return nil , fmt .Errorf ("expected admission.Request in ctx: %w" , err )
172+ }
173+ if req .Kind .Kind != "CronJob" {
174+ return nil , fmt .Errorf ("expected Kind CronJob got %q" , req .Kind .Kind )
175+ }
176+ castedObj , ok := newObj .(* CronJob )
177+ if ! ok {
178+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , newObj )
179+ }
180+ cronjoblog .Info ("default" , "name" , castedObj .GetName ())
133181
134- return nil , r .validateCronJob ()
182+ return nil , v .validateCronJob (castedObj )
135183}
136184
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 )
185+ // ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type
186+ func (v * CronJobCustomValidator ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
187+ cronjoblog .Info ("Deletion Validation for CronJob" )
188+ req , err := admission .RequestFromContext (ctx )
189+ if err != nil {
190+ return nil , fmt .Errorf ("expected admission.Request in ctx: %w" , err )
191+ }
192+ if req .Kind .Kind != "CronJob" {
193+ return nil , fmt .Errorf ("expected Kind CronJob got %q" , req .Kind .Kind )
194+ }
195+ castedObj , ok := obj .(* CronJob )
196+ if ! ok {
197+ return nil , fmt .Errorf ("expected a CronJob object but got %T" , obj )
198+ }
199+ cronjoblog .Info ("default" , "name" , castedObj .GetName ())
140200
141201 // TODO(user): fill in your validation logic upon object deletion.
202+
142203 return nil , nil
143204}
144205
145206/*
146207We validate the name and the spec of the CronJob.
147208*/
148209
149- func (r * CronJob ) validateCronJob () error {
210+ func (v * CronJobCustomValidator ) validateCronJob (castedObj * CronJob ) error {
150211 var allErrs field.ErrorList
151- if err := r .validateCronJobName (); err != nil {
212+ if err := v .validateCronJobName (castedObj ); err != nil {
152213 allErrs = append (allErrs , err )
153214 }
154- if err := r .validateCronJobSpec (); err != nil {
215+ if err := v .validateCronJobSpec (castedObj ); err != nil {
155216 allErrs = append (allErrs , err )
156217 }
157218 if len (allErrs ) == 0 {
@@ -160,7 +221,7 @@ func (r *CronJob) validateCronJob() error {
160221
161222 return apierrors .NewInvalid (
162223 schema.GroupKind {Group : "batch.tutorial.kubebuilder.io" , Kind : "CronJob" },
163- r .Name , allErrs )
224+ castedObj .Name , allErrs )
164225}
165226
166227/*
@@ -173,11 +234,11 @@ declaring validation by running `controller-gen crd -w`,
173234or [here](/reference/markers/crd-validation.md).
174235*/
175236
176- func (r * CronJob ) validateCronJobSpec () * field.Error {
237+ func (v * CronJobCustomValidator ) validateCronJobSpec (castedObj * CronJob ) * field.Error {
177238 // The field helpers from the kubernetes API machinery help us return nicely
178239 // structured validation errors.
179240 return validateScheduleFormat (
180- r .Spec .Schedule ,
241+ castedObj .Spec .Schedule ,
181242 field .NewPath ("spec" ).Child ("schedule" ))
182243}
183244
@@ -202,15 +263,15 @@ the apimachinery repo, so we can't declaratively validate it using
202263the validation schema.
203264*/
204265
205- func (r * CronJob ) validateCronJobName () * field.Error {
206- if len (r .ObjectMeta .Name ) > validationutils .DNS1035LabelMaxLength - 11 {
207- // The job name length is 63 character like all Kubernetes objects
266+ func (v * CronJobCustomValidator ) validateCronJobName (castedObj * CronJob ) * field.Error {
267+ if len (castedObj .ObjectMeta .Name ) > validationutils .DNS1035LabelMaxLength - 11 {
268+ // The job name length is 63 characters like all Kubernetes objects
208269 // (which must fit in a DNS subdomain). The cronjob controller appends
209270 // a 11-character suffix to the cronjob (`-$TIMESTAMP`) when creating
210271 // a job. The job name length limit is 63 characters. Therefore cronjob
211272 // names must have length <= 63-11=52. If we don't validate this here,
212273 // then job creation will fail later.
213- return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), r .Name , "must be no more than 52 characters" )
274+ return field .Invalid (field .NewPath ("metadata" ).Child ("name" ), castedObj .Name , "must be no more than 52 characters" )
214275 }
215276 return nil
216277}
0 commit comments