cronjob_webhook.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. Copyright 2023.
  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. package v1
  14. import (
  15. "github.com/robfig/cron"
  16. apierrors "k8s.io/apimachinery/pkg/api/errors"
  17. "k8s.io/apimachinery/pkg/runtime"
  18. "k8s.io/apimachinery/pkg/runtime/schema"
  19. validationutils "k8s.io/apimachinery/pkg/util/validation"
  20. "k8s.io/apimachinery/pkg/util/validation/field"
  21. ctrl "sigs.k8s.io/controller-runtime"
  22. logf "sigs.k8s.io/controller-runtime/pkg/log"
  23. "sigs.k8s.io/controller-runtime/pkg/webhook"
  24. )
  25. // log is for logging in this package.
  26. var cronjoblog = logf.Log.WithName("cronjob-resource")
  27. func (r *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error {
  28. return ctrl.NewWebhookManagedBy(mgr).
  29. For(r).
  30. Complete()
  31. }
  32. // TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
  33. //+kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,sideEffects=None,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob.kb.io,admissionReviewVersions=v1
  34. var _ webhook.Defaulter = &CronJob{}
  35. // Default implements webhook.Defaulter so a webhook will be registered for the type
  36. func (r *CronJob) Default() {
  37. cronjoblog.Info("default", "name", r.Name)
  38. // TODO(user): fill in your defaulting logic.
  39. if r.Spec.ConcurrencyPolicy == "" {
  40. r.Spec.ConcurrencyPolicy = AllowConcurrent
  41. }
  42. if r.Spec.Suspend == nil {
  43. r.Spec.Suspend = new(bool)
  44. }
  45. if r.Spec.SuccessfulJobsHistoryLimit == nil {
  46. r.Spec.SuccessfulJobsHistoryLimit = new(int32)
  47. *r.Spec.SuccessfulJobsHistoryLimit = 3
  48. }
  49. if r.Spec.FailedJobsHistoryLimit == nil {
  50. r.Spec.FailedJobsHistoryLimit = new(int32)
  51. *r.Spec.FailedJobsHistoryLimit = 1
  52. }
  53. }
  54. // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
  55. //+kubebuilder:webhook:path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,sideEffects=None,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=vcronjob.kb.io,admissionReviewVersions=v1
  56. var _ webhook.Validator = &CronJob{}
  57. // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
  58. func (r *CronJob) ValidateCreate() error {
  59. cronjoblog.Info("validate create", "name", r.Name)
  60. // TODO(user): fill in your validation logic upon object creation.
  61. return nil
  62. }
  63. // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
  64. func (r *CronJob) ValidateUpdate(old runtime.Object) error {
  65. cronjoblog.Info("validate update", "name", r.Name)
  66. // TODO(user): fill in your validation logic upon object update.
  67. return nil
  68. }
  69. // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
  70. func (r *CronJob) ValidateDelete() error {
  71. cronjoblog.Info("validate delete", "name", r.Name)
  72. // TODO(user): fill in your validation logic upon object deletion.
  73. return nil
  74. }
  75. func (r *CronJob) validateCronJob() error {
  76. var allErrs field.ErrorList
  77. if err := r.validateCronJobName(); err != nil {
  78. allErrs = append(allErrs, err)
  79. }
  80. if err := r.validateCronJobSpec(); err != nil {
  81. allErrs = append(allErrs, err)
  82. }
  83. if len(allErrs) == 0 {
  84. return nil
  85. }
  86. return apierrors.NewInvalid(
  87. schema.GroupKind{Group: "batch.tutorial.kubebuilder.io", Kind: "CronJob"},
  88. r.Name, allErrs)
  89. }
  90. func (r *CronJob) validateCronJobSpec() *field.Error {
  91. // The field helpers from the kubernetes API machinery help us return nicely
  92. // structured validation errors.
  93. return validateScheduleFormat(
  94. r.Spec.Schedule,
  95. field.NewPath("spec").Child("schedule"))
  96. }
  97. func validateScheduleFormat(schedule string, fldPath *field.Path) *field.Error {
  98. if _, err := cron.ParseStandard(schedule); err != nil {
  99. return field.Invalid(fldPath, schedule, err.Error())
  100. }
  101. return nil
  102. }
  103. func (r *CronJob) validateCronJobName() *field.Error {
  104. if len(r.ObjectMeta.Name) > validationutils.DNS1035LabelMaxLength-11 {
  105. // The job name length is 63 character like all Kubernetes objects
  106. // (which must fit in a DNS subdomain). The cronjob controller appends
  107. // a 11-character suffix to the cronjob (`-$TIMESTAMP`) when creating
  108. // a job. The job name length limit is 63 characters. Therefore cronjob
  109. // names must have length <= 63-11=52. If we don't validate this here,
  110. // then job creation will fail later.
  111. return field.Invalid(field.NewPath("metadata").Child("name"), r.Name, "must be no more than 52 characters")
  112. }
  113. return nil
  114. }