1
16
17 package storage
18
19 import (
20 "context"
21 "fmt"
22
23 apierrors "k8s.io/apimachinery/pkg/api/errors"
24 metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28 "k8s.io/apimachinery/pkg/watch"
29 "k8s.io/apiserver/pkg/registry/generic"
30 genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
31 "k8s.io/apiserver/pkg/registry/rest"
32 "k8s.io/apiserver/pkg/storage"
33 storageerr "k8s.io/apiserver/pkg/storage/errors"
34 "k8s.io/apiserver/pkg/util/dryrun"
35 api "k8s.io/kubernetes/pkg/apis/core"
36 "k8s.io/kubernetes/pkg/printers"
37 printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
38 printerstorage "k8s.io/kubernetes/pkg/printers/storage"
39 "k8s.io/kubernetes/pkg/registry/core/namespace"
40 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
41 )
42
43
44 type REST struct {
45 store *genericregistry.Store
46 status *genericregistry.Store
47 }
48
49
50 type StatusREST struct {
51 store *genericregistry.Store
52 }
53
54
55 type FinalizeREST struct {
56 store *genericregistry.Store
57 }
58
59
60 func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, *FinalizeREST, error) {
61 store := &genericregistry.Store{
62 NewFunc: func() runtime.Object { return &api.Namespace{} },
63 NewListFunc: func() runtime.Object { return &api.NamespaceList{} },
64 PredicateFunc: namespace.MatchNamespace,
65 DefaultQualifiedResource: api.Resource("namespaces"),
66 SingularQualifiedResource: api.Resource("namespace"),
67
68 CreateStrategy: namespace.Strategy,
69 UpdateStrategy: namespace.Strategy,
70 DeleteStrategy: namespace.Strategy,
71 ResetFieldsStrategy: namespace.Strategy,
72 ReturnDeletedObject: true,
73
74 ShouldDeleteDuringUpdate: ShouldDeleteNamespaceDuringUpdate,
75
76 TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
77 }
78 options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: namespace.GetAttrs}
79 if err := store.CompleteWithOptions(options); err != nil {
80 return nil, nil, nil, err
81 }
82
83 statusStore := *store
84 statusStore.UpdateStrategy = namespace.StatusStrategy
85 statusStore.ResetFieldsStrategy = namespace.StatusStrategy
86
87 finalizeStore := *store
88 finalizeStore.UpdateStrategy = namespace.FinalizeStrategy
89 finalizeStore.ResetFieldsStrategy = namespace.FinalizeStrategy
90
91 return &REST{store: store, status: &statusStore}, &StatusREST{store: &statusStore}, &FinalizeREST{store: &finalizeStore}, nil
92 }
93
94 func (r *REST) NamespaceScoped() bool {
95 return r.store.NamespaceScoped()
96 }
97
98 var _ rest.SingularNameProvider = &REST{}
99
100 func (r *REST) GetSingularName() string {
101 return r.store.GetSingularName()
102 }
103
104 func (r *REST) New() runtime.Object {
105 return r.store.New()
106 }
107
108
109 func (r *REST) Destroy() {
110 r.store.Destroy()
111 }
112
113 func (r *REST) NewList() runtime.Object {
114 return r.store.NewList()
115 }
116
117 func (r *REST) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
118 return r.store.List(ctx, options)
119 }
120
121 func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
122 return r.store.Create(ctx, obj, createValidation, options)
123 }
124
125 func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
126 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options)
127 }
128
129 func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
130 return r.store.Get(ctx, name, options)
131 }
132
133 func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) {
134 return r.store.Watch(ctx, options)
135 }
136
137
138 func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
139 nsObj, err := r.Get(ctx, name, &metav1.GetOptions{})
140 if err != nil {
141 return nil, false, err
142 }
143
144 namespace := nsObj.(*api.Namespace)
145
146
147 if options == nil {
148 options = metav1.NewDeleteOptions(0)
149 }
150 if options.Preconditions == nil {
151 options.Preconditions = &metav1.Preconditions{}
152 }
153 if options.Preconditions.UID == nil {
154 options.Preconditions.UID = &namespace.UID
155 } else if *options.Preconditions.UID != namespace.UID {
156 err = apierrors.NewConflict(
157 api.Resource("namespaces"),
158 name,
159 fmt.Errorf("Precondition failed: UID in precondition: %v, UID in object meta: %v", *options.Preconditions.UID, namespace.UID),
160 )
161 return nil, false, err
162 }
163 if options.Preconditions.ResourceVersion != nil && *options.Preconditions.ResourceVersion != namespace.ResourceVersion {
164 err = apierrors.NewConflict(
165 api.Resource("namespaces"),
166 name,
167 fmt.Errorf("Precondition failed: ResourceVersion in precondition: %v, ResourceVersion in object meta: %v", *options.Preconditions.ResourceVersion, namespace.ResourceVersion),
168 )
169 return nil, false, err
170 }
171
172
173
174 if namespace.DeletionTimestamp.IsZero() {
175 key, err := r.store.KeyFunc(ctx, name)
176 if err != nil {
177 return nil, false, err
178 }
179
180 preconditions := storage.Preconditions{UID: options.Preconditions.UID, ResourceVersion: options.Preconditions.ResourceVersion}
181
182 out := r.store.NewFunc()
183 err = r.store.Storage.GuaranteedUpdate(
184 ctx, key, out, false, &preconditions,
185 storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) {
186 existingNamespace, ok := existing.(*api.Namespace)
187 if !ok {
188
189 return nil, fmt.Errorf("expected *api.Namespace, got %v", existing)
190 }
191 if err := deleteValidation(ctx, existingNamespace); err != nil {
192 return nil, err
193 }
194
195 if existingNamespace.DeletionTimestamp.IsZero() {
196 now := metav1.Now()
197 existingNamespace.DeletionTimestamp = &now
198 }
199
200 if existingNamespace.Status.Phase != api.NamespaceTerminating {
201 existingNamespace.Status.Phase = api.NamespaceTerminating
202 }
203
204
205 currentFinalizers := map[string]bool{}
206 for _, f := range existingNamespace.Finalizers {
207 currentFinalizers[f] = true
208 }
209
210 shouldHaveFinalizers := map[string]bool{
211 metav1.FinalizerOrphanDependents: shouldHaveOrphanFinalizer(options, currentFinalizers[metav1.FinalizerOrphanDependents]),
212 metav1.FinalizerDeleteDependents: shouldHaveDeleteDependentsFinalizer(options, currentFinalizers[metav1.FinalizerDeleteDependents]),
213 }
214
215 changeNeeded := false
216 for finalizer, shouldHave := range shouldHaveFinalizers {
217 changeNeeded = currentFinalizers[finalizer] != shouldHave || changeNeeded
218 if shouldHave {
219 currentFinalizers[finalizer] = true
220 } else {
221 delete(currentFinalizers, finalizer)
222 }
223 }
224
225 if changeNeeded {
226 newFinalizers := []string{}
227 for f := range currentFinalizers {
228 newFinalizers = append(newFinalizers, f)
229 }
230 existingNamespace.Finalizers = newFinalizers
231 }
232 return existingNamespace, nil
233 }),
234 dryrun.IsDryRun(options.DryRun),
235 nil,
236 )
237
238 if err != nil {
239 err = storageerr.InterpretGetError(err, api.Resource("namespaces"), name)
240 err = storageerr.InterpretUpdateError(err, api.Resource("namespaces"), name)
241 if _, ok := err.(*apierrors.StatusError); !ok {
242 err = apierrors.NewInternalError(err)
243 }
244 return nil, false, err
245 }
246
247 return out, false, nil
248 }
249
250
251 if len(namespace.Spec.Finalizers) != 0 {
252 return namespace, false, nil
253 }
254 return r.store.Delete(ctx, name, deleteValidation, options)
255 }
256
257
258 func ShouldDeleteNamespaceDuringUpdate(ctx context.Context, key string, obj, existing runtime.Object) bool {
259 ns, ok := obj.(*api.Namespace)
260 if !ok {
261 utilruntime.HandleError(fmt.Errorf("unexpected type %T", obj))
262 return false
263 }
264 return len(ns.Spec.Finalizers) == 0 && genericregistry.ShouldDeleteDuringUpdate(ctx, key, obj, existing)
265 }
266
267 func shouldHaveOrphanFinalizer(options *metav1.DeleteOptions, haveOrphanFinalizer bool) bool {
268
269 if options.OrphanDependents != nil {
270 return *options.OrphanDependents
271 }
272 if options.PropagationPolicy != nil {
273 return *options.PropagationPolicy == metav1.DeletePropagationOrphan
274 }
275 return haveOrphanFinalizer
276 }
277
278 func shouldHaveDeleteDependentsFinalizer(options *metav1.DeleteOptions, haveDeleteDependentsFinalizer bool) bool {
279
280 if options.OrphanDependents != nil {
281 return *options.OrphanDependents == false
282 }
283 if options.PropagationPolicy != nil {
284 return *options.PropagationPolicy == metav1.DeletePropagationForeground
285 }
286 return haveDeleteDependentsFinalizer
287 }
288
289 func (e *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
290 return e.store.ConvertToTable(ctx, object, tableOptions)
291 }
292
293
294 var _ rest.ShortNamesProvider = &REST{}
295
296
297 func (r *REST) ShortNames() []string {
298 return []string{"ns"}
299 }
300
301 var _ rest.StorageVersionProvider = &REST{}
302
303 func (r *REST) StorageVersion() runtime.GroupVersioner {
304 return r.store.StorageVersion()
305 }
306
307
308 func (r *REST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
309 return r.store.GetResetFields()
310 }
311 func (r *StatusREST) New() runtime.Object {
312 return r.store.New()
313 }
314
315
316 func (r *StatusREST) Destroy() {
317
318
319 }
320
321
322 func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
323 return r.store.Get(ctx, name, options)
324 }
325
326
327 func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
328
329
330 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
331 }
332
333
334 func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
335 return r.store.GetResetFields()
336 }
337
338 func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
339 return r.store.ConvertToTable(ctx, object, tableOptions)
340 }
341
342 func (r *FinalizeREST) New() runtime.Object {
343 return r.store.New()
344 }
345
346
347 func (r *FinalizeREST) Destroy() {
348
349
350 }
351
352
353 func (r *FinalizeREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
354
355
356 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
357 }
358
359
360 func (r *FinalizeREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
361 return r.store.GetResetFields()
362 }
363
View as plain text