validation.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. Copyright 2019 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. apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
  16. metavalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
  17. "k8s.io/apimachinery/pkg/util/sets"
  18. "k8s.io/apimachinery/pkg/util/validation"
  19. "k8s.io/apimachinery/pkg/util/validation/field"
  20. api "k8s.io/kubernetes/pkg/apis/core"
  21. apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
  22. "k8s.io/kubernetes/pkg/apis/discovery"
  23. )
  24. var (
  25. supportedAddressTypes = sets.NewString(
  26. string(discovery.AddressTypeIPv4),
  27. string(discovery.AddressTypeIPv6),
  28. string(discovery.AddressTypeFQDN),
  29. )
  30. deprecatedAddressTypes = sets.NewString(
  31. string(discovery.AddressTypeIP),
  32. )
  33. supportedPortProtocols = sets.NewString(
  34. string(api.ProtocolTCP),
  35. string(api.ProtocolUDP),
  36. string(api.ProtocolSCTP),
  37. )
  38. maxTopologyLabels = 16
  39. maxAddresses = 100
  40. maxPorts = 100
  41. maxEndpoints = 1000
  42. )
  43. // ValidateEndpointSliceName can be used to check whether the given endpoint
  44. // slice name is valid. Prefix indicates this name will be used as part of
  45. // generation, in which case trailing dashes are allowed.
  46. var ValidateEndpointSliceName = apimachineryvalidation.NameIsDNSSubdomain
  47. // ValidateEndpointSlice validates an EndpointSlice.
  48. func ValidateEndpointSlice(endpointSlice *discovery.EndpointSlice, validAddressTypes sets.String) field.ErrorList {
  49. allErrs := apivalidation.ValidateObjectMeta(&endpointSlice.ObjectMeta, true, ValidateEndpointSliceName, field.NewPath("metadata"))
  50. allErrs = append(allErrs, validateAddressType(endpointSlice.AddressType, validAddressTypes)...)
  51. allErrs = append(allErrs, validateEndpoints(endpointSlice.Endpoints, endpointSlice.AddressType, field.NewPath("endpoints"))...)
  52. allErrs = append(allErrs, validatePorts(endpointSlice.Ports, field.NewPath("ports"))...)
  53. return allErrs
  54. }
  55. // ValidateEndpointSliceCreate validates an EndpointSlice when it is created.
  56. func ValidateEndpointSliceCreate(endpointSlice *discovery.EndpointSlice) field.ErrorList {
  57. return ValidateEndpointSlice(endpointSlice, supportedAddressTypes)
  58. }
  59. // ValidateEndpointSliceUpdate validates an EndpointSlice when it is updated.
  60. func ValidateEndpointSliceUpdate(newEndpointSlice, oldEndpointSlice *discovery.EndpointSlice) field.ErrorList {
  61. allErrs := ValidateEndpointSlice(newEndpointSlice, supportedAddressTypes.Union(deprecatedAddressTypes))
  62. allErrs = append(allErrs, apivalidation.ValidateImmutableField(newEndpointSlice.AddressType, oldEndpointSlice.AddressType, field.NewPath("addressType"))...)
  63. return allErrs
  64. }
  65. func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.AddressType, fldPath *field.Path) field.ErrorList {
  66. allErrs := field.ErrorList{}
  67. if len(endpoints) > maxEndpoints {
  68. allErrs = append(allErrs, field.TooMany(fldPath, len(endpoints), maxEndpoints))
  69. return allErrs
  70. }
  71. for i, endpoint := range endpoints {
  72. idxPath := fldPath.Index(i)
  73. addressPath := idxPath.Child("addresses")
  74. if len(endpoint.Addresses) == 0 {
  75. allErrs = append(allErrs, field.Required(addressPath, "must contain at least 1 address"))
  76. } else if len(endpoint.Addresses) > maxAddresses {
  77. allErrs = append(allErrs, field.TooMany(addressPath, len(endpoint.Addresses), maxAddresses))
  78. }
  79. for i, address := range endpoint.Addresses {
  80. // This validates known address types, unknown types fall through
  81. // and do not get validated.
  82. switch addrType {
  83. case discovery.AddressTypeIP:
  84. for _, msg := range validation.IsValidIP(address) {
  85. allErrs = append(allErrs, field.Invalid(addressPath.Index(i), address, msg))
  86. }
  87. case discovery.AddressTypeIPv4:
  88. allErrs = append(allErrs, validation.IsValidIPv4Address(addressPath.Index(i), address)...)
  89. case discovery.AddressTypeIPv6:
  90. allErrs = append(allErrs, validation.IsValidIPv6Address(addressPath.Index(i), address)...)
  91. case discovery.AddressTypeFQDN:
  92. allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
  93. }
  94. }
  95. topologyPath := idxPath.Child("topology")
  96. if len(endpoint.Topology) > maxTopologyLabels {
  97. allErrs = append(allErrs, field.TooMany(topologyPath, len(endpoint.Topology), maxTopologyLabels))
  98. }
  99. allErrs = append(allErrs, metavalidation.ValidateLabels(endpoint.Topology, topologyPath)...)
  100. if endpoint.Hostname != nil {
  101. allErrs = append(allErrs, apivalidation.ValidateDNS1123Label(*endpoint.Hostname, idxPath.Child("hostname"))...)
  102. }
  103. }
  104. return allErrs
  105. }
  106. func validatePorts(endpointPorts []discovery.EndpointPort, fldPath *field.Path) field.ErrorList {
  107. allErrs := field.ErrorList{}
  108. if len(endpointPorts) > maxPorts {
  109. allErrs = append(allErrs, field.TooMany(fldPath, len(endpointPorts), maxPorts))
  110. return allErrs
  111. }
  112. portNames := sets.String{}
  113. for i, endpointPort := range endpointPorts {
  114. idxPath := fldPath.Index(i)
  115. if len(*endpointPort.Name) > 0 {
  116. allErrs = append(allErrs, apivalidation.ValidateDNS1123Label(*endpointPort.Name, idxPath.Child("name"))...)
  117. }
  118. if portNames.Has(*endpointPort.Name) {
  119. allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), endpointPort.Name))
  120. } else {
  121. portNames.Insert(*endpointPort.Name)
  122. }
  123. if endpointPort.Protocol == nil {
  124. allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
  125. } else if !supportedPortProtocols.Has(string(*endpointPort.Protocol)) {
  126. allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), *endpointPort.Protocol, supportedPortProtocols.List()))
  127. }
  128. if endpointPort.AppProtocol != nil {
  129. for _, msg := range validation.IsQualifiedName(*endpointPort.AppProtocol) {
  130. allErrs = append(allErrs, field.Invalid(idxPath.Child("appProtocol"), endpointPort.AppProtocol, msg))
  131. }
  132. }
  133. }
  134. return allErrs
  135. }
  136. func validateAddressType(addressType discovery.AddressType, validAddressTypes sets.String) field.ErrorList {
  137. allErrs := field.ErrorList{}
  138. if addressType == "" {
  139. allErrs = append(allErrs, field.Required(field.NewPath("addressType"), ""))
  140. } else if !validAddressTypes.Has(string(addressType)) {
  141. allErrs = append(allErrs, field.NotSupported(field.NewPath("addressType"), addressType, validAddressTypes.List()))
  142. }
  143. return allErrs
  144. }