1
16
17 package customresourcedefinition
18
19 import (
20 "context"
21 "fmt"
22
23 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
24 apierrors "k8s.io/apimachinery/pkg/api/errors"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apiserver/pkg/registry/generic"
28 genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
29 "k8s.io/apiserver/pkg/registry/rest"
30 "k8s.io/apiserver/pkg/storage"
31 storageerr "k8s.io/apiserver/pkg/storage/errors"
32 "k8s.io/apiserver/pkg/util/dryrun"
33 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
34 )
35
36
37 type REST struct {
38 *genericregistry.Store
39 }
40
41
42 func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*REST, error) {
43 strategy := NewStrategy(scheme)
44
45 store := &genericregistry.Store{
46 NewFunc: func() runtime.Object { return &apiextensions.CustomResourceDefinition{} },
47 NewListFunc: func() runtime.Object { return &apiextensions.CustomResourceDefinitionList{} },
48 PredicateFunc: MatchCustomResourceDefinition,
49 DefaultQualifiedResource: apiextensions.Resource("customresourcedefinitions"),
50 SingularQualifiedResource: apiextensions.Resource("customresourcedefinition"),
51
52 CreateStrategy: strategy,
53 UpdateStrategy: strategy,
54 DeleteStrategy: strategy,
55 ResetFieldsStrategy: strategy,
56
57
58 TableConvertor: rest.NewDefaultTableConvertor(apiextensions.Resource("customresourcedefinitions")),
59 }
60 options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
61 if err := store.CompleteWithOptions(options); err != nil {
62 return nil, err
63 }
64 return &REST{store}, nil
65 }
66
67
68 var _ rest.ShortNamesProvider = &REST{}
69
70
71 func (r *REST) ShortNames() []string {
72 return []string{"crd", "crds"}
73 }
74
75
76 var _ rest.CategoriesProvider = &REST{}
77
78
79 func (r *REST) Categories() []string {
80 return []string{"api-extensions"}
81 }
82
83
84 func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
85 obj, err := r.Get(ctx, name, &metav1.GetOptions{})
86 if err != nil {
87 return nil, false, err
88 }
89
90 crd := obj.(*apiextensions.CustomResourceDefinition)
91
92
93 if options == nil {
94 options = metav1.NewDeleteOptions(0)
95 }
96 if options.Preconditions == nil {
97 options.Preconditions = &metav1.Preconditions{}
98 }
99 if options.Preconditions.UID == nil {
100 options.Preconditions.UID = &crd.UID
101 } else if *options.Preconditions.UID != crd.UID {
102 err = apierrors.NewConflict(
103 apiextensions.Resource("customresourcedefinitions"),
104 name,
105 fmt.Errorf("Precondition failed: UID in precondition: %v, UID in object meta: %v", *options.Preconditions.UID, crd.UID),
106 )
107 return nil, false, err
108 }
109 if options.Preconditions.ResourceVersion != nil && *options.Preconditions.ResourceVersion != crd.ResourceVersion {
110 err = apierrors.NewConflict(
111 apiextensions.Resource("customresourcedefinitions"),
112 name,
113 fmt.Errorf("Precondition failed: ResourceVersion in precondition: %v, ResourceVersion in object meta: %v", *options.Preconditions.ResourceVersion, crd.ResourceVersion),
114 )
115 return nil, false, err
116 }
117
118
119 if crd.DeletionTimestamp.IsZero() {
120 key, err := r.Store.KeyFunc(ctx, name)
121 if err != nil {
122 return nil, false, err
123 }
124
125 preconditions := storage.Preconditions{UID: options.Preconditions.UID, ResourceVersion: options.Preconditions.ResourceVersion}
126
127 out := r.Store.NewFunc()
128 err = r.Store.Storage.GuaranteedUpdate(
129 ctx, key, out, false, &preconditions,
130 storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) {
131 existingCRD, ok := existing.(*apiextensions.CustomResourceDefinition)
132 if !ok {
133
134 return nil, fmt.Errorf("expected *apiextensions.CustomResourceDefinition, got %v", existing)
135 }
136 if err := deleteValidation(ctx, existingCRD); err != nil {
137 return nil, err
138 }
139
140
141 if existingCRD.DeletionTimestamp.IsZero() {
142 now := metav1.Now()
143 existingCRD.DeletionTimestamp = &now
144 }
145
146 if !apiextensions.CRDHasFinalizer(existingCRD, apiextensions.CustomResourceCleanupFinalizer) {
147 existingCRD.Finalizers = append(existingCRD.Finalizers, apiextensions.CustomResourceCleanupFinalizer)
148 }
149
150 apiextensions.SetCRDCondition(existingCRD, apiextensions.CustomResourceDefinitionCondition{
151 Type: apiextensions.Terminating,
152 Status: apiextensions.ConditionTrue,
153 Reason: "InstanceDeletionPending",
154 Message: "CustomResourceDefinition marked for deletion; CustomResource deletion will begin soon",
155 })
156 return existingCRD, nil
157 }),
158 dryrun.IsDryRun(options.DryRun),
159 nil,
160 )
161
162 if err != nil {
163 err = storageerr.InterpretGetError(err, apiextensions.Resource("customresourcedefinitions"), name)
164 err = storageerr.InterpretUpdateError(err, apiextensions.Resource("customresourcedefinitions"), name)
165 if _, ok := err.(*apierrors.StatusError); !ok {
166 err = apierrors.NewInternalError(err)
167 }
168 return nil, false, err
169 }
170
171 return out, false, nil
172 }
173
174 return r.Store.Delete(ctx, name, deleteValidation, options)
175 }
176
177
178
179 func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
180 statusStore := *rest.Store
181 statusStore.CreateStrategy = nil
182 statusStore.DeleteStrategy = nil
183 statusStrategy := NewStatusStrategy(scheme)
184 statusStore.UpdateStrategy = statusStrategy
185 statusStore.ResetFieldsStrategy = statusStrategy
186 return &StatusREST{store: &statusStore}
187 }
188
189 type StatusREST struct {
190 store *genericregistry.Store
191 }
192
193 var _ = rest.Patcher(&StatusREST{})
194
195 func (r *StatusREST) New() runtime.Object {
196 return &apiextensions.CustomResourceDefinition{}
197 }
198
199
200 func (r *StatusREST) Destroy() {
201
202
203 }
204
205
206 func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
207 return r.store.Get(ctx, name, options)
208 }
209
210
211 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) {
212
213
214 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
215 }
216
217
218 func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
219 return r.store.GetResetFields()
220 }
221
View as plain text