1
16
17
18
19 package storage
20
21 import (
22 "context"
23 "fmt"
24
25 "k8s.io/apimachinery/pkg/api/errors"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/labels"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/managedfields"
31 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
32 "k8s.io/apiserver/pkg/registry/generic"
33 genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
34 "k8s.io/apiserver/pkg/registry/rest"
35 "k8s.io/klog/v2"
36 "k8s.io/kubernetes/pkg/apis/autoscaling"
37 autoscalingv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
38 "k8s.io/kubernetes/pkg/apis/autoscaling/validation"
39 api "k8s.io/kubernetes/pkg/apis/core"
40 extensionsv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
41 "k8s.io/kubernetes/pkg/printers"
42 printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
43 printerstorage "k8s.io/kubernetes/pkg/printers/storage"
44 "k8s.io/kubernetes/pkg/registry/core/replicationcontroller"
45 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
46 )
47
48
49 type ControllerStorage struct {
50 Controller *REST
51 Status *StatusREST
52 Scale *ScaleREST
53 }
54
55
56 func ReplicasPathMappings() managedfields.ResourcePathMappings {
57 return replicasPathInReplicationController
58 }
59
60
61 var replicasPathInReplicationController = managedfields.ResourcePathMappings{
62 schema.GroupVersion{Group: "", Version: "v1"}.String(): fieldpath.MakePathOrDie("spec", "replicas"),
63 }
64
65 func NewStorage(optsGetter generic.RESTOptionsGetter) (ControllerStorage, error) {
66 controllerREST, statusREST, err := NewREST(optsGetter)
67 if err != nil {
68 return ControllerStorage{}, err
69 }
70
71 return ControllerStorage{
72 Controller: controllerREST,
73 Status: statusREST,
74 Scale: &ScaleREST{store: controllerREST.Store},
75 }, nil
76 }
77
78 type REST struct {
79 *genericregistry.Store
80 }
81
82
83 func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
84 store := &genericregistry.Store{
85 NewFunc: func() runtime.Object { return &api.ReplicationController{} },
86 NewListFunc: func() runtime.Object { return &api.ReplicationControllerList{} },
87 PredicateFunc: replicationcontroller.MatchController,
88 DefaultQualifiedResource: api.Resource("replicationcontrollers"),
89 SingularQualifiedResource: api.Resource("replicationcontroller"),
90
91 CreateStrategy: replicationcontroller.Strategy,
92 UpdateStrategy: replicationcontroller.Strategy,
93 DeleteStrategy: replicationcontroller.Strategy,
94 ResetFieldsStrategy: replicationcontroller.Strategy,
95
96 TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
97 }
98 options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: replicationcontroller.GetAttrs}
99 if err := store.CompleteWithOptions(options); err != nil {
100 return nil, nil, err
101 }
102
103 statusStore := *store
104 statusStore.UpdateStrategy = replicationcontroller.StatusStrategy
105 statusStore.ResetFieldsStrategy = replicationcontroller.StatusStrategy
106
107 return &REST{store}, &StatusREST{store: &statusStore}, nil
108 }
109
110
111 var _ rest.ShortNamesProvider = &REST{}
112
113
114 func (r *REST) ShortNames() []string {
115 return []string{"rc"}
116 }
117
118
119 var _ rest.CategoriesProvider = &REST{}
120
121
122 func (r *REST) Categories() []string {
123 return []string{"all"}
124 }
125
126
127 type StatusREST struct {
128 store *genericregistry.Store
129 }
130
131 func (r *StatusREST) New() runtime.Object {
132 return &api.ReplicationController{}
133 }
134
135
136 func (r *StatusREST) Destroy() {
137
138
139 }
140
141
142 func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
143 return r.store.Get(ctx, name, options)
144 }
145
146
147 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) {
148
149
150 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
151 }
152
153
154 func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
155 return r.store.GetResetFields()
156 }
157
158 func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
159 return r.store.ConvertToTable(ctx, object, tableOptions)
160 }
161
162 type ScaleREST struct {
163 store *genericregistry.Store
164 }
165
166
167 var _ = rest.Patcher(&ScaleREST{})
168 var _ = rest.GroupVersionKindProvider(&ScaleREST{})
169
170 func (r *ScaleREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
171 switch containingGV {
172 case extensionsv1beta1.SchemeGroupVersion:
173 return extensionsv1beta1.SchemeGroupVersion.WithKind("Scale")
174 default:
175 return autoscalingv1.SchemeGroupVersion.WithKind("Scale")
176 }
177 }
178
179
180 func (r *ScaleREST) New() runtime.Object {
181 return &autoscaling.Scale{}
182 }
183
184
185 func (r *ScaleREST) Destroy() {
186
187
188 }
189
190 func (r *ScaleREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
191 obj, err := r.store.Get(ctx, name, options)
192 if err != nil {
193 return nil, errors.NewNotFound(autoscaling.Resource("replicationcontrollers/scale"), name)
194 }
195 rc := obj.(*api.ReplicationController)
196 return scaleFromRC(rc), nil
197 }
198
199 func (r *ScaleREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
200 obj, _, err := r.store.Update(
201 ctx,
202 name,
203 &scaleUpdatedObjectInfo{name, objInfo},
204 toScaleCreateValidation(createValidation),
205 toScaleUpdateValidation(updateValidation),
206 false,
207 options,
208 )
209 if err != nil {
210 return nil, false, err
211 }
212 rc := obj.(*api.ReplicationController)
213 return scaleFromRC(rc), false, nil
214 }
215
216 func (r *ScaleREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
217 return r.store.ConvertToTable(ctx, object, tableOptions)
218 }
219
220 func toScaleCreateValidation(f rest.ValidateObjectFunc) rest.ValidateObjectFunc {
221 return func(ctx context.Context, obj runtime.Object) error {
222 return f(ctx, scaleFromRC(obj.(*api.ReplicationController)))
223 }
224 }
225
226 func toScaleUpdateValidation(f rest.ValidateObjectUpdateFunc) rest.ValidateObjectUpdateFunc {
227 return func(ctx context.Context, obj, old runtime.Object) error {
228 return f(
229 ctx,
230 scaleFromRC(obj.(*api.ReplicationController)),
231 scaleFromRC(old.(*api.ReplicationController)),
232 )
233 }
234 }
235
236
237 func scaleFromRC(rc *api.ReplicationController) *autoscaling.Scale {
238 return &autoscaling.Scale{
239 ObjectMeta: metav1.ObjectMeta{
240 Name: rc.Name,
241 Namespace: rc.Namespace,
242 UID: rc.UID,
243 ResourceVersion: rc.ResourceVersion,
244 CreationTimestamp: rc.CreationTimestamp,
245 },
246 Spec: autoscaling.ScaleSpec{
247 Replicas: rc.Spec.Replicas,
248 },
249 Status: autoscaling.ScaleStatus{
250 Replicas: rc.Status.Replicas,
251 Selector: labels.SelectorFromSet(rc.Spec.Selector).String(),
252 },
253 }
254 }
255
256
257 type scaleUpdatedObjectInfo struct {
258 name string
259 reqObjInfo rest.UpdatedObjectInfo
260 }
261
262 func (i *scaleUpdatedObjectInfo) Preconditions() *metav1.Preconditions {
263 return i.reqObjInfo.Preconditions()
264 }
265
266 func (i *scaleUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runtime.Object) (runtime.Object, error) {
267 replicationcontroller, ok := oldObj.DeepCopyObject().(*api.ReplicationController)
268 if !ok {
269 return nil, errors.NewBadRequest(fmt.Sprintf("expected existing object type to be ReplicationController, got %T", replicationcontroller))
270 }
271
272 if len(replicationcontroller.ResourceVersion) == 0 {
273 return nil, errors.NewNotFound(api.Resource("replicationcontrollers/scale"), i.name)
274 }
275
276 groupVersion := schema.GroupVersion{Group: "", Version: "v1"}
277 if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
278 requestGroupVersion := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
279 if _, ok := replicasPathInReplicationController[requestGroupVersion.String()]; ok {
280 groupVersion = requestGroupVersion
281 } else {
282 klog.Fatalf("Unrecognized group/version in request info %q", requestGroupVersion.String())
283 }
284 }
285
286 managedFieldsHandler := managedfields.NewScaleHandler(
287 replicationcontroller.ManagedFields,
288 groupVersion,
289 replicasPathInReplicationController,
290 )
291
292
293 oldScale := scaleFromRC(replicationcontroller)
294 scaleManagedFields, err := managedFieldsHandler.ToSubresource()
295 if err != nil {
296 return nil, err
297 }
298 oldScale.ManagedFields = scaleManagedFields
299
300
301 newScaleObj, err := i.reqObjInfo.UpdatedObject(ctx, oldScale)
302 if err != nil {
303 return nil, err
304 }
305 if newScaleObj == nil {
306 return nil, errors.NewBadRequest("nil update passed to Scale")
307 }
308 scale, ok := newScaleObj.(*autoscaling.Scale)
309 if !ok {
310 return nil, errors.NewBadRequest(fmt.Sprintf("expected input object type to be Scale, but %T", newScaleObj))
311 }
312
313
314 if errs := validation.ValidateScale(scale); len(errs) > 0 {
315 return nil, errors.NewInvalid(autoscaling.Kind("Scale"), replicationcontroller.Name, errs)
316 }
317
318
319 if len(scale.UID) > 0 && scale.UID != replicationcontroller.UID {
320 return nil, errors.NewConflict(
321 api.Resource("replicationcontrollers/scale"),
322 replicationcontroller.Name,
323 fmt.Errorf("Precondition failed: UID in precondition: %v, UID in object meta: %v", scale.UID, replicationcontroller.UID),
324 )
325 }
326
327
328 replicationcontroller.Spec.Replicas = scale.Spec.Replicas
329 replicationcontroller.ResourceVersion = scale.ResourceVersion
330
331 updatedEntries, err := managedFieldsHandler.ToParent(scale.ManagedFields)
332 if err != nil {
333 return nil, err
334 }
335 replicationcontroller.ManagedFields = updatedEntries
336
337 return replicationcontroller, nil
338 }
339
View as plain text