1
16
17 package statefulset
18
19 import (
20 "context"
21
22 apiequality "k8s.io/apimachinery/pkg/api/equality"
23 "k8s.io/apimachinery/pkg/runtime"
24 "k8s.io/apimachinery/pkg/util/validation/field"
25 "k8s.io/apiserver/pkg/registry/rest"
26 "k8s.io/apiserver/pkg/storage/names"
27 utilfeature "k8s.io/apiserver/pkg/util/feature"
28 "k8s.io/kubernetes/pkg/api/legacyscheme"
29 pvcutil "k8s.io/kubernetes/pkg/api/persistentvolumeclaim"
30 "k8s.io/kubernetes/pkg/api/pod"
31 "k8s.io/kubernetes/pkg/apis/apps"
32 "k8s.io/kubernetes/pkg/apis/apps/validation"
33 "k8s.io/kubernetes/pkg/features"
34 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
35 )
36
37
38 type statefulSetStrategy struct {
39 runtime.ObjectTyper
40 names.NameGenerator
41 }
42
43
44 var Strategy = statefulSetStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
45
46
47 var _ = rest.GarbageCollectionDeleteStrategy(Strategy)
48
49
50 func (statefulSetStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy {
51 return rest.DeleteDependents
52 }
53
54
55 func (statefulSetStrategy) NamespaceScoped() bool {
56 return true
57 }
58
59
60
61 func (statefulSetStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
62 fields := map[fieldpath.APIVersion]*fieldpath.Set{
63 "apps/v1": fieldpath.NewSet(
64 fieldpath.MakePathOrDie("status"),
65 ),
66 }
67
68 return fields
69 }
70
71
72 func (statefulSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
73 statefulSet := obj.(*apps.StatefulSet)
74
75 statefulSet.Status = apps.StatefulSetStatus{}
76
77 statefulSet.Generation = 1
78
79 dropStatefulSetDisabledFields(statefulSet, nil)
80 pod.DropDisabledTemplateFields(&statefulSet.Spec.Template, nil)
81 }
82
83
84 func maxUnavailableInUse(statefulset *apps.StatefulSet) bool {
85 if statefulset == nil {
86 return false
87 }
88 if statefulset.Spec.UpdateStrategy.RollingUpdate == nil {
89 return false
90 }
91
92 return statefulset.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable != nil
93 }
94
95
96 func (statefulSetStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
97 newStatefulSet := obj.(*apps.StatefulSet)
98 oldStatefulSet := old.(*apps.StatefulSet)
99
100 newStatefulSet.Status = oldStatefulSet.Status
101
102 dropStatefulSetDisabledFields(newStatefulSet, oldStatefulSet)
103 pod.DropDisabledTemplateFields(&newStatefulSet.Spec.Template, &oldStatefulSet.Spec.Template)
104
105
106
107
108 if !apiequality.Semantic.DeepEqual(oldStatefulSet.Spec, newStatefulSet.Spec) {
109 newStatefulSet.Generation = oldStatefulSet.Generation + 1
110 }
111 }
112
113
114
115
116
117
118
119
120 func dropStatefulSetDisabledFields(newSS *apps.StatefulSet, oldSS *apps.StatefulSet) {
121 if !utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetAutoDeletePVC) {
122 if oldSS == nil || oldSS.Spec.PersistentVolumeClaimRetentionPolicy == nil {
123 newSS.Spec.PersistentVolumeClaimRetentionPolicy = nil
124 }
125 }
126 if !utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) && !maxUnavailableInUse(oldSS) {
127 if newSS.Spec.UpdateStrategy.RollingUpdate != nil {
128 newSS.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = nil
129 }
130 }
131 if !utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetStartOrdinal) {
132 if oldSS == nil || oldSS.Spec.Ordinals == nil {
133
134 newSS.Spec.Ordinals = nil
135 }
136 }
137 }
138
139
140 func (statefulSetStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
141 statefulSet := obj.(*apps.StatefulSet)
142 opts := pod.GetValidationOptionsFromPodTemplate(&statefulSet.Spec.Template, nil)
143 return validation.ValidateStatefulSet(statefulSet, opts)
144 }
145
146
147 func (statefulSetStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
148 newStatefulSet := obj.(*apps.StatefulSet)
149 warnings := pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newStatefulSet.Spec.Template, nil)
150 for i, pvc := range newStatefulSet.Spec.VolumeClaimTemplates {
151 warnings = append(warnings, pvcutil.GetWarningsForPersistentVolumeClaimSpec(field.NewPath("spec", "volumeClaimTemplates").Index(i), pvc.Spec)...)
152 }
153 return warnings
154 }
155
156
157 func (statefulSetStrategy) Canonicalize(obj runtime.Object) {
158 }
159
160
161 func (statefulSetStrategy) AllowCreateOnUpdate() bool {
162 return false
163 }
164
165
166 func (statefulSetStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
167 newStatefulSet := obj.(*apps.StatefulSet)
168 oldStatefulSet := old.(*apps.StatefulSet)
169
170 opts := pod.GetValidationOptionsFromPodTemplate(&newStatefulSet.Spec.Template, &oldStatefulSet.Spec.Template)
171 return validation.ValidateStatefulSetUpdate(newStatefulSet, oldStatefulSet, opts)
172 }
173
174
175 func (statefulSetStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
176 var warnings []string
177 newStatefulSet := obj.(*apps.StatefulSet)
178 oldStatefulSet := old.(*apps.StatefulSet)
179 if newStatefulSet.Generation != oldStatefulSet.Generation {
180 warnings = pod.GetWarningsForPodTemplate(ctx, field.NewPath("spec", "template"), &newStatefulSet.Spec.Template, &oldStatefulSet.Spec.Template)
181 }
182 for i, pvc := range newStatefulSet.Spec.VolumeClaimTemplates {
183 warnings = append(warnings, pvcutil.GetWarningsForPersistentVolumeClaimSpec(field.NewPath("spec", "volumeClaimTemplates").Index(i).Child("Spec"), pvc.Spec)...)
184 }
185
186 return warnings
187 }
188
189
190 func (statefulSetStrategy) AllowUnconditionalUpdate() bool {
191 return true
192 }
193
194 type statefulSetStatusStrategy struct {
195 statefulSetStrategy
196 }
197
198
199 var StatusStrategy = statefulSetStatusStrategy{Strategy}
200
201
202
203 func (statefulSetStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
204 return map[fieldpath.APIVersion]*fieldpath.Set{
205 "apps/v1": fieldpath.NewSet(
206 fieldpath.MakePathOrDie("spec"),
207 ),
208 }
209 }
210
211
212 func (statefulSetStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
213 newStatefulSet := obj.(*apps.StatefulSet)
214 oldStatefulSet := old.(*apps.StatefulSet)
215
216 newStatefulSet.Spec = oldStatefulSet.Spec
217 }
218
219
220 func (statefulSetStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
221
222 return validation.ValidateStatefulSetStatusUpdate(obj.(*apps.StatefulSet), old.(*apps.StatefulSet))
223 }
224
225
226 func (statefulSetStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
227 return nil
228 }
229
View as plain text