strategy.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. Copyright 2014 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 service
  14. import (
  15. "context"
  16. "fmt"
  17. "k8s.io/apimachinery/pkg/runtime"
  18. "k8s.io/apimachinery/pkg/util/validation/field"
  19. "k8s.io/apiserver/pkg/storage/names"
  20. utilfeature "k8s.io/apiserver/pkg/util/feature"
  21. "k8s.io/kubernetes/pkg/api/legacyscheme"
  22. api "k8s.io/kubernetes/pkg/apis/core"
  23. "k8s.io/kubernetes/pkg/apis/core/validation"
  24. "k8s.io/kubernetes/pkg/features"
  25. )
  26. // svcStrategy implements behavior for Services
  27. type svcStrategy struct {
  28. runtime.ObjectTyper
  29. names.NameGenerator
  30. }
  31. // Services is the default logic that applies when creating and updating Service
  32. // objects.
  33. var Strategy = svcStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
  34. // NamespaceScoped is true for services.
  35. func (svcStrategy) NamespaceScoped() bool {
  36. return true
  37. }
  38. // PrepareForCreate clears fields that are not allowed to be set by end users on creation.
  39. func (svcStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
  40. service := obj.(*api.Service)
  41. service.Status = api.ServiceStatus{}
  42. dropServiceDisabledFields(service, nil)
  43. }
  44. // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
  45. func (svcStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
  46. newService := obj.(*api.Service)
  47. oldService := old.(*api.Service)
  48. newService.Status = oldService.Status
  49. dropServiceDisabledFields(newService, oldService)
  50. }
  51. // Validate validates a new service.
  52. func (svcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
  53. service := obj.(*api.Service)
  54. allErrs := validation.ValidateService(service)
  55. allErrs = append(allErrs, validation.ValidateConditionalService(service, nil)...)
  56. return allErrs
  57. }
  58. // Canonicalize normalizes the object after validation.
  59. func (svcStrategy) Canonicalize(obj runtime.Object) {
  60. }
  61. func (svcStrategy) AllowCreateOnUpdate() bool {
  62. return true
  63. }
  64. func (svcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
  65. allErrs := validation.ValidateServiceUpdate(obj.(*api.Service), old.(*api.Service))
  66. allErrs = append(allErrs, validation.ValidateConditionalService(obj.(*api.Service), old.(*api.Service))...)
  67. return allErrs
  68. }
  69. func (svcStrategy) AllowUnconditionalUpdate() bool {
  70. return true
  71. }
  72. func (svcStrategy) Export(ctx context.Context, obj runtime.Object, exact bool) error {
  73. t, ok := obj.(*api.Service)
  74. if !ok {
  75. // unexpected programmer error
  76. return fmt.Errorf("unexpected object: %v", obj)
  77. }
  78. // TODO: service does not yet have a prepare create strategy (see above)
  79. t.Status = api.ServiceStatus{}
  80. if exact {
  81. return nil
  82. }
  83. if t.Spec.ClusterIP != api.ClusterIPNone {
  84. t.Spec.ClusterIP = ""
  85. }
  86. if t.Spec.Type == api.ServiceTypeNodePort {
  87. for i := range t.Spec.Ports {
  88. t.Spec.Ports[i].NodePort = 0
  89. }
  90. }
  91. return nil
  92. }
  93. // dropServiceDisabledFields drops fields that are not used if their associated feature gates
  94. // are not enabled. The typical pattern is:
  95. // if !utilfeature.DefaultFeatureGate.Enabled(features.MyFeature) && !myFeatureInUse(oldSvc) {
  96. // newSvc.Spec.MyFeature = nil
  97. // }
  98. func dropServiceDisabledFields(newSvc *api.Service, oldSvc *api.Service) {
  99. // Drop IPFamily if DualStack is not enabled
  100. if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) && !serviceIPFamilyInUse(oldSvc) {
  101. newSvc.Spec.IPFamily = nil
  102. }
  103. // Drop TopologyKeys if ServiceTopology is not enabled
  104. if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) && !topologyKeysInUse(oldSvc) {
  105. newSvc.Spec.TopologyKeys = nil
  106. }
  107. }
  108. // returns true if svc.Spec.ServiceIPFamily field is in use
  109. func serviceIPFamilyInUse(svc *api.Service) bool {
  110. if svc == nil {
  111. return false
  112. }
  113. if svc.Spec.IPFamily != nil {
  114. return true
  115. }
  116. return false
  117. }
  118. // returns true if svc.Spec.TopologyKeys field is in use
  119. func topologyKeysInUse(svc *api.Service) bool {
  120. if svc == nil {
  121. return false
  122. }
  123. return len(svc.Spec.TopologyKeys) > 0
  124. }
  125. type serviceStatusStrategy struct {
  126. svcStrategy
  127. }
  128. // StatusStrategy is the default logic invoked when updating service status.
  129. var StatusStrategy = serviceStatusStrategy{Strategy}
  130. // PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
  131. func (serviceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
  132. newService := obj.(*api.Service)
  133. oldService := old.(*api.Service)
  134. // status changes are not allowed to update spec
  135. newService.Spec = oldService.Spec
  136. }
  137. // ValidateUpdate is the default update validation for an end user updating status
  138. func (serviceStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
  139. return validation.ValidateServiceStatusUpdate(obj.(*api.Service), old.(*api.Service))
  140. }