diff --git a/pkg/registry/core/pod/storage/storage.go b/pkg/registry/core/pod/storage/storage.go index 5bdf342d068..8aaa358d085 100644 --- a/pkg/registry/core/pod/storage/storage.go +++ b/pkg/registry/core/pod/storage/storage.go @@ -54,6 +54,7 @@ type PodStorage struct { Eviction *EvictionREST Status *StatusREST EphemeralContainers *EphemeralContainersREST + Resize *ResizeREST Log *podrest.LogREST Proxy *podrest.ProxyREST Exec *podrest.ExecREST @@ -100,6 +101,8 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet statusStore.ResetFieldsStrategy = registrypod.StatusStrategy ephemeralContainersStore := *store ephemeralContainersStore.UpdateStrategy = registrypod.EphemeralContainersStrategy + resizeStore := *store + resizeStore.UpdateStrategy = registrypod.ResizeStrategy bindingREST := &BindingREST{store: store} return PodStorage{ @@ -109,6 +112,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet Eviction: newEvictionStorage(&statusStore, podDisruptionBudgetClient), Status: &StatusREST{store: &statusStore}, EphemeralContainers: &EphemeralContainersREST{store: &ephemeralContainersStore}, + Resize: &ResizeREST{store: &resizeStore}, Log: &podrest.LogREST{Store: store, KubeletConn: k}, Proxy: &podrest.ProxyREST{Store: store, ProxyTransport: proxyTransport}, Exec: &podrest.ExecREST{Store: store, KubeletConn: k}, @@ -365,3 +369,33 @@ func (r *EphemeralContainersREST) Update(ctx context.Context, name string, objIn // subresources should never allow create on update. return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) } + +// ResizeREST implements the REST endpoint for resizing Pod containers. +type ResizeREST struct { + store *genericregistry.Store +} + +var _ = rest.Patcher(&ResizeREST{}) + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *ResizeREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +// New creates a new pod resource +func (r *ResizeREST) New() runtime.Object { + return &api.Pod{} +} + +// Destroy cleans up resources on shutdown. +func (r *ResizeREST) Destroy() { + // Given that underlying store is shared with REST, + // we don't destroy it here explicitly. +} + +// Update alters the resource fields in PodSpec +func (r *ResizeREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + // We are explicitly setting forceAllowCreate to false in the call to the underlying storage because + // subresources should never allow create on update. + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) +} diff --git a/pkg/registry/core/pod/strategy.go b/pkg/registry/core/pod/strategy.go index 541fc43a220..a596e5f11a9 100644 --- a/pkg/registry/core/pod/strategy.go +++ b/pkg/registry/core/pod/strategy.go @@ -101,15 +101,6 @@ func (podStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object newPod := obj.(*api.Pod) oldPod := old.(*api.Pod) newPod.Status = oldPod.Status - - if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) { - // With support for in-place pod resizing, container resources are now mutable. - // If container resources are updated with new resource requests values, a pod resize is - // desired. The status of this request is reflected by setting Resize field to "Proposed" - // as a signal to the caller that the request is being considered. - podutil.MarkPodProposedForResize(oldPod, newPod) - } - podutil.DropDisabledPodFields(newPod, oldPod) } @@ -286,6 +277,34 @@ func (podEphemeralContainersStrategy) WarningsOnUpdate(ctx context.Context, obj, return nil } +type podResizeStrategy struct { + podStrategy +} + +// ResizeStrategy wraps and exports the used podStrategy for the storage package. +var ResizeStrategy = podResizeStrategy{Strategy} + +func (podResizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newPod := obj.(*api.Pod) + oldPod := old.(*api.Pod) + + podutil.MarkPodProposedForResize(oldPod, newPod) + podutil.DropDisabledPodFields(newPod, oldPod) +} + +func (podResizeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + newPod := obj.(*api.Pod) + oldPod := old.(*api.Pod) + opts := podutil.GetValidationOptionsFromPodSpecAndMeta(&newPod.Spec, &oldPod.Spec, &newPod.ObjectMeta, &oldPod.ObjectMeta) + opts.ResourceIsPod = true + return nil +} + +// WarningsOnUpdate returns warnings for the given update. +func (podResizeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + // GetAttrs returns labels and fields of a given object for filtering purposes. func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { pod, ok := obj.(*api.Pod) diff --git a/pkg/registry/core/rest/storage_core.go b/pkg/registry/core/rest/storage_core.go index bac4b133de1..b5c4e39ec95 100644 --- a/pkg/registry/core/rest/storage_core.go +++ b/pkg/registry/core/rest/storage_core.go @@ -242,6 +242,9 @@ func (p *legacyProvider) NewRESTStorage(apiResourceConfigSource serverstorage.AP storage[resource+"/eviction"] = podStorage.Eviction } storage[resource+"/ephemeralcontainers"] = podStorage.EphemeralContainers + if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) { + storage[resource+"/resize"] = podStorage.Resize + } } if resource := "bindings"; apiResourceConfigSource.ResourceEnabled(corev1.SchemeGroupVersion.WithResource(resource)) { storage[resource] = podStorage.LegacyBinding