validation.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. Copyright 2018 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. package validation
  14. import (
  15. "errors"
  16. "fmt"
  17. v1 "k8s.io/api/core/v1"
  18. utilerrors "k8s.io/apimachinery/pkg/util/errors"
  19. "k8s.io/apimachinery/pkg/util/sets"
  20. "k8s.io/apimachinery/pkg/util/validation"
  21. "k8s.io/apimachinery/pkg/util/validation/field"
  22. componentbasevalidation "k8s.io/component-base/config/validation"
  23. v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  24. "k8s.io/kubernetes/pkg/scheduler/apis/config"
  25. )
  26. // ValidateKubeSchedulerConfiguration ensures validation of the KubeSchedulerConfiguration struct
  27. func ValidateKubeSchedulerConfiguration(cc *config.KubeSchedulerConfiguration) field.ErrorList {
  28. allErrs := field.ErrorList{}
  29. allErrs = append(allErrs, componentbasevalidation.ValidateClientConnectionConfiguration(&cc.ClientConnection, field.NewPath("clientConnection"))...)
  30. allErrs = append(allErrs, ValidateKubeSchedulerLeaderElectionConfiguration(&cc.LeaderElection, field.NewPath("leaderElection"))...)
  31. if len(cc.SchedulerName) == 0 {
  32. allErrs = append(allErrs, field.Required(field.NewPath("schedulerName"), ""))
  33. }
  34. for _, msg := range validation.IsValidSocketAddr(cc.HealthzBindAddress) {
  35. allErrs = append(allErrs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, msg))
  36. }
  37. for _, msg := range validation.IsValidSocketAddr(cc.MetricsBindAddress) {
  38. allErrs = append(allErrs, field.Invalid(field.NewPath("metricsBindAddress"), cc.MetricsBindAddress, msg))
  39. }
  40. if cc.HardPodAffinitySymmetricWeight < 0 || cc.HardPodAffinitySymmetricWeight > 100 {
  41. allErrs = append(allErrs, field.Invalid(field.NewPath("hardPodAffinitySymmetricWeight"), cc.HardPodAffinitySymmetricWeight, "not in valid range [0-100]"))
  42. }
  43. if cc.PercentageOfNodesToScore < 0 || cc.PercentageOfNodesToScore > 100 {
  44. allErrs = append(allErrs, field.Invalid(field.NewPath("percentageOfNodesToScore"),
  45. cc.PercentageOfNodesToScore, "not in valid range [0-100]"))
  46. }
  47. if cc.PodInitialBackoffSeconds <= 0 {
  48. allErrs = append(allErrs, field.Invalid(field.NewPath("podInitialBackoffSeconds"),
  49. cc.PodInitialBackoffSeconds, "must be greater than 0"))
  50. }
  51. if cc.PodMaxBackoffSeconds < cc.PodInitialBackoffSeconds {
  52. allErrs = append(allErrs, field.Invalid(field.NewPath("podMaxBackoffSeconds"),
  53. cc.PodMaxBackoffSeconds, "must be greater than or equal to PodInitialBackoffSeconds"))
  54. }
  55. return allErrs
  56. }
  57. // ValidateKubeSchedulerLeaderElectionConfiguration ensures validation of the KubeSchedulerLeaderElectionConfiguration struct
  58. func ValidateKubeSchedulerLeaderElectionConfiguration(cc *config.KubeSchedulerLeaderElectionConfiguration, fldPath *field.Path) field.ErrorList {
  59. allErrs := field.ErrorList{}
  60. if !cc.LeaderElectionConfiguration.LeaderElect {
  61. return allErrs
  62. }
  63. allErrs = append(allErrs, componentbasevalidation.ValidateLeaderElectionConfiguration(&cc.LeaderElectionConfiguration, field.NewPath("leaderElectionConfiguration"))...)
  64. return allErrs
  65. }
  66. // ValidatePolicy checks for errors in the Config
  67. // It does not return early so that it can find as many errors as possible
  68. func ValidatePolicy(policy config.Policy) error {
  69. var validationErrors []error
  70. priorities := make(map[string]config.PriorityPolicy, len(policy.Priorities))
  71. for _, priority := range policy.Priorities {
  72. if priority.Weight <= 0 || priority.Weight >= config.MaxWeight {
  73. validationErrors = append(validationErrors, fmt.Errorf("Priority %s should have a positive weight applied to it or it has overflown", priority.Name))
  74. }
  75. validationErrors = append(validationErrors, validateCustomPriorities(priorities, priority))
  76. }
  77. binders := 0
  78. extenderManagedResources := sets.NewString()
  79. for _, extender := range policy.Extenders {
  80. if len(extender.PrioritizeVerb) > 0 && extender.Weight <= 0 {
  81. validationErrors = append(validationErrors, fmt.Errorf("Priority for extender %s should have a positive weight applied to it", extender.URLPrefix))
  82. }
  83. if extender.BindVerb != "" {
  84. binders++
  85. }
  86. for _, resource := range extender.ManagedResources {
  87. errs := validateExtendedResourceName(v1.ResourceName(resource.Name))
  88. if len(errs) != 0 {
  89. validationErrors = append(validationErrors, errs...)
  90. }
  91. if extenderManagedResources.Has(resource.Name) {
  92. validationErrors = append(validationErrors, fmt.Errorf("Duplicate extender managed resource name %s", string(resource.Name)))
  93. }
  94. extenderManagedResources.Insert(resource.Name)
  95. }
  96. }
  97. if binders > 1 {
  98. validationErrors = append(validationErrors, fmt.Errorf("Only one extender can implement bind, found %v", binders))
  99. }
  100. if policy.HardPodAffinitySymmetricWeight < 0 || policy.HardPodAffinitySymmetricWeight > 100 {
  101. validationErrors = append(validationErrors, field.Invalid(field.NewPath("hardPodAffinitySymmetricWeight"), policy.HardPodAffinitySymmetricWeight, "not in valid range [0-100]"))
  102. }
  103. return utilerrors.NewAggregate(validationErrors)
  104. }
  105. // validateCustomPriorities validates that:
  106. // 1. RequestedToCapacityRatioRedeclared custom priority cannot be declared multiple times,
  107. // 2. LabelPreference/ServiceAntiAffinity custom priorities can be declared multiple times,
  108. // however the weights for each custom priority type should be the same.
  109. func validateCustomPriorities(priorities map[string]config.PriorityPolicy, priority config.PriorityPolicy) error {
  110. verifyRedeclaration := func(priorityType string) error {
  111. if existing, alreadyDeclared := priorities[priorityType]; alreadyDeclared {
  112. return fmt.Errorf("Priority %q redeclares custom priority %q, from:%q", priority.Name, priorityType, existing.Name)
  113. }
  114. priorities[priorityType] = priority
  115. return nil
  116. }
  117. verifyDifferentWeights := func(priorityType string) error {
  118. if existing, alreadyDeclared := priorities[priorityType]; alreadyDeclared {
  119. if existing.Weight != priority.Weight {
  120. return fmt.Errorf("%s priority %q has a different weight with %q", priorityType, priority.Name, existing.Name)
  121. }
  122. }
  123. priorities[priorityType] = priority
  124. return nil
  125. }
  126. if priority.Argument != nil {
  127. if priority.Argument.LabelPreference != nil {
  128. if err := verifyDifferentWeights("LabelPreference"); err != nil {
  129. return err
  130. }
  131. } else if priority.Argument.ServiceAntiAffinity != nil {
  132. if err := verifyDifferentWeights("ServiceAntiAffinity"); err != nil {
  133. return err
  134. }
  135. } else if priority.Argument.RequestedToCapacityRatioArguments != nil {
  136. if err := verifyRedeclaration("RequestedToCapacityRatio"); err != nil {
  137. return err
  138. }
  139. } else {
  140. return fmt.Errorf("No priority arguments set for priority %s", priority.Name)
  141. }
  142. }
  143. return nil
  144. }
  145. // validateExtendedResourceName checks whether the specified name is a valid
  146. // extended resource name.
  147. func validateExtendedResourceName(name v1.ResourceName) []error {
  148. var validationErrors []error
  149. for _, msg := range validation.IsQualifiedName(string(name)) {
  150. validationErrors = append(validationErrors, errors.New(msg))
  151. }
  152. if len(validationErrors) != 0 {
  153. return validationErrors
  154. }
  155. if !v1helper.IsExtendedResourceName(name) {
  156. validationErrors = append(validationErrors, fmt.Errorf("%s is an invalid extended resource name", name))
  157. }
  158. return validationErrors
  159. }