From 40f8fb222491de331bb578413684a3388608e708 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 31 Mar 2021 15:39:41 -0400 Subject: [PATCH 1/6] Register Eviction v1 --- pkg/registry/core/pod/storage/eviction.go | 2 +- staging/src/k8s.io/api/policy/v1/register.go | 1 + staging/src/k8s.io/api/policy/v1/types.go | 19 +++++++++ .../typed/core/v1/fake/fake_pod_expansion.go | 21 +++++++++- .../kubernetes/typed/core/v1/pod_expansion.go | 27 +++++++++++-- .../typed/policy/v1/eviction_expansion.go | 40 +++++++++++++++++++ .../policy/v1/fake/fake_eviction_expansion.go | 37 +++++++++++++++++ 7 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction_expansion.go create mode 100644 staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go diff --git a/pkg/registry/core/pod/storage/eviction.go b/pkg/registry/core/pod/storage/eviction.go index a4aa690cf8e..4e09a899209 100644 --- a/pkg/registry/core/pod/storage/eviction.go +++ b/pkg/registry/core/pod/storage/eviction.go @@ -73,7 +73,7 @@ var _ = rest.GroupVersionKindProvider(&EvictionREST{}) // GroupVersionKind specifies a particular GroupVersionKind to discovery func (r *EvictionREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "Eviction"} + return schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "Eviction"} } // New creates a new eviction resource diff --git a/staging/src/k8s.io/api/policy/v1/register.go b/staging/src/k8s.io/api/policy/v1/register.go index 603c49b9cef..7fb9fd3e1f1 100644 --- a/staging/src/k8s.io/api/policy/v1/register.go +++ b/staging/src/k8s.io/api/policy/v1/register.go @@ -44,6 +44,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &PodDisruptionBudget{}, &PodDisruptionBudgetList{}, + &Eviction{}, ) // Add the watch version that applies metav1.AddToGroupVersion(scheme, SchemeGroupVersion) diff --git a/staging/src/k8s.io/api/policy/v1/types.go b/staging/src/k8s.io/api/policy/v1/types.go index 65bf768d866..f621e784f76 100644 --- a/staging/src/k8s.io/api/policy/v1/types.go +++ b/staging/src/k8s.io/api/policy/v1/types.go @@ -148,3 +148,22 @@ type PodDisruptionBudgetList struct { // Items is a list of PodDisruptionBudgets Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"` } + +// +genclient +// +genclient:noVerbs +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Eviction evicts a pod from its node subject to certain policies and safety constraints. +// This is a subresource of Pod. A request to cause such an eviction is +// created by POSTing to .../pods//evictions. +type Eviction struct { + metav1.TypeMeta `json:",inline"` + + // ObjectMeta describes the pod that is being evicted. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // DeleteOptions may be provided + // +optional + DeleteOptions *metav1.DeleteOptions `json:"deleteOptions,omitempty" protobuf:"bytes,2,opt,name=deleteOptions"` +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go index d9a718a56f3..31f71b0e48e 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod_expansion.go @@ -24,7 +24,8 @@ import ( "strings" v1 "k8s.io/api/core/v1" - policy "k8s.io/api/policy/v1beta1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" restclient "k8s.io/client-go/rest" @@ -78,7 +79,23 @@ func (c *FakePods) GetLogs(name string, opts *v1.PodLogOptions) *restclient.Requ return fakeClient.Request() } -func (c *FakePods) Evict(ctx context.Context, eviction *policy.Eviction) error { +func (c *FakePods) Evict(ctx context.Context, eviction *policyv1beta1.Eviction) error { + return c.EvictV1beta1(ctx, eviction) +} + +func (c *FakePods) EvictV1(ctx context.Context, eviction *policyv1.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = podsResource + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} + +func (c *FakePods) EvictV1beta1(ctx context.Context, eviction *policyv1beta1.Eviction) error { action := core.CreateActionImpl{} action.Verb = "create" action.Namespace = c.ns diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod_expansion.go b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod_expansion.go index 759fe0ff4a2..8b6e0e932f9 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod_expansion.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod_expansion.go @@ -20,7 +20,8 @@ import ( "context" v1 "k8s.io/api/core/v1" - policy "k8s.io/api/policy/v1beta1" + policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/net" "k8s.io/client-go/kubernetes/scheme" @@ -30,7 +31,16 @@ import ( // The PodExpansion interface allows manually adding extra methods to the PodInterface. type PodExpansion interface { Bind(ctx context.Context, binding *v1.Binding, opts metav1.CreateOptions) error - Evict(ctx context.Context, eviction *policy.Eviction) error + // Evict submits a policy/v1beta1 Eviction request to the pod's eviction subresource. + // Equivalent to calling EvictV1beta1. + // Deprecated: Use EvictV1() (supported in 1.22+) or EvictV1beta1(). + Evict(ctx context.Context, eviction *policyv1beta1.Eviction) error + // EvictV1 submits a policy/v1 Eviction request to the pod's eviction subresource. + // Supported in 1.22+. + EvictV1(ctx context.Context, eviction *policyv1.Eviction) error + // EvictV1beta1 submits a policy/v1beta1 Eviction request to the pod's eviction subresource. + // Supported in 1.22+. + EvictV1beta1(ctx context.Context, eviction *policyv1beta1.Eviction) error GetLogs(name string, opts *v1.PodLogOptions) *restclient.Request ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper } @@ -40,7 +50,18 @@ func (c *pods) Bind(ctx context.Context, binding *v1.Binding, opts metav1.Create return c.client.Post().Namespace(c.ns).Resource("pods").Name(binding.Name).VersionedParams(&opts, scheme.ParameterCodec).SubResource("binding").Body(binding).Do(ctx).Error() } -func (c *pods) Evict(ctx context.Context, eviction *policy.Eviction) error { +// Evict submits a policy/v1beta1 Eviction request to the pod's eviction subresource. +// Equivalent to calling EvictV1beta1. +// Deprecated: Use EvictV1() (supported in 1.22+) or EvictV1beta1(). +func (c *pods) Evict(ctx context.Context, eviction *policyv1beta1.Eviction) error { + return c.client.Post().Namespace(c.ns).Resource("pods").Name(eviction.Name).SubResource("eviction").Body(eviction).Do(ctx).Error() +} + +func (c *pods) EvictV1beta1(ctx context.Context, eviction *policyv1beta1.Eviction) error { + return c.client.Post().Namespace(c.ns).Resource("pods").Name(eviction.Name).SubResource("eviction").Body(eviction).Do(ctx).Error() +} + +func (c *pods) EvictV1(ctx context.Context, eviction *policyv1.Eviction) error { return c.client.Post().Namespace(c.ns).Resource("pods").Name(eviction.Name).SubResource("eviction").Body(eviction).Do(ctx).Error() } diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction_expansion.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction_expansion.go new file mode 100644 index 00000000000..853187feb5d --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction_expansion.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + policy "k8s.io/api/policy/v1" +) + +// The EvictionExpansion interface allows manually adding extra methods to the ScaleInterface. +type EvictionExpansion interface { + Evict(ctx context.Context, eviction *policy.Eviction) error +} + +func (c *evictions) Evict(ctx context.Context, eviction *policy.Eviction) error { + return c.client.Post(). + AbsPath("/api/v1"). + Namespace(eviction.Namespace). + Resource("pods"). + Name(eviction.Name). + SubResource("eviction"). + Body(eviction). + Do(ctx). + Error() +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go new file mode 100644 index 00000000000..1b6b4ade17e --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction_expansion.go @@ -0,0 +1,37 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fake + +import ( + "context" + + policy "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + core "k8s.io/client-go/testing" +) + +func (c *FakeEvictions) Evict(ctx context.Context, eviction *policy.Eviction) error { + action := core.CreateActionImpl{} + action.Verb = "create" + action.Namespace = c.ns + action.Resource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} + action.Subresource = "eviction" + action.Object = eviction + + _, err := c.Fake.Invokes(action, eviction) + return err +} From e22cd7dbc4d6b2c2de844811d15ed630312d2201 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 31 Mar 2021 15:39:55 -0400 Subject: [PATCH 2/6] Generated files Change-Id: Ibd7ac0392fd52ae7ce2f6864aefb47bf1b74f8c3 --- api/openapi-spec/swagger.json | 68 ++-- pkg/apis/policy/v1/zz_generated.conversion.go | 32 ++ .../src/k8s.io/api/policy/v1/generated.pb.go | 328 +++++++++++++++--- .../src/k8s.io/api/policy/v1/generated.proto | 13 + .../policy/v1/types_swagger_doc_generated.go | 10 + .../api/policy/v1/zz_generated.deepcopy.go | 31 ++ .../api/testdata/HEAD/policy.v1.Eviction.json | 55 +++ .../api/testdata/HEAD/policy.v1.Eviction.pb | Bin 0 -> 274 bytes .../api/testdata/HEAD/policy.v1.Eviction.yaml | 40 +++ .../applyconfigurations/internal/internal.go | 16 + .../applyconfigurations/policy/v1/eviction.go | 256 ++++++++++++++ .../client-go/applyconfigurations/utils.go | 2 + .../kubernetes/typed/policy/v1/eviction.go | 48 +++ .../typed/policy/v1/fake/fake_eviction.go | 25 ++ .../policy/v1/fake/fake_policy_client.go | 4 + .../typed/policy/v1/policy_client.go | 5 + .../client-go/listers/policy/v1/eviction.go | 99 ++++++ .../listers/policy/v1/expansion_generated.go | 8 + 18 files changed, 953 insertions(+), 87 deletions(-) create mode 100644 staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.json create mode 100644 staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.pb create mode 100644 staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.yaml create mode 100644 staging/src/k8s.io/client-go/applyconfigurations/policy/v1/eviction.go create mode 100644 staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction.go create mode 100644 staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go create mode 100644 staging/src/k8s.io/client-go/listers/policy/v1/eviction.go diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 9ae4ae9d849..e99c0eb6c21 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -13595,6 +13595,35 @@ }, "type": "object" }, + "io.k8s.api.policy.v1.Eviction": { + "description": "Eviction evicts a pod from its node subject to certain policies and safety constraints. This is a subresource of Pod. A request to cause such an eviction is created by POSTing to .../pods//evictions.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + "type": "string" + }, + "deleteOptions": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions", + "description": "DeleteOptions may be provided" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", + "description": "ObjectMeta describes the pod that is being evicted." + } + }, + "type": "object", + "x-kubernetes-group-version-kind": [ + { + "group": "policy", + "kind": "Eviction", + "version": "v1" + } + ] + }, "io.k8s.api.policy.v1.PodDisruptionBudget": { "description": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", "properties": { @@ -13779,35 +13808,6 @@ }, "type": "object" }, - "io.k8s.api.policy.v1beta1.Eviction": { - "description": "Eviction evicts a pod from its node subject to certain policies and safety constraints. This is a subresource of Pod. A request to cause such an eviction is created by POSTing to .../pods//evictions.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "deleteOptions": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions", - "description": "DeleteOptions may be provided" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "ObjectMeta describes the pod that is being evicted." - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "policy", - "kind": "Eviction", - "version": "v1beta1" - } - ] - }, "io.k8s.api.policy.v1beta1.FSGroupStrategyOptions": { "description": "FSGroupStrategyOptions defines the strategy type and options used to create the strategy.", "properties": { @@ -25130,7 +25130,7 @@ "name": "body", "required": true, "schema": { - "$ref": "#/definitions/io.k8s.api.policy.v1beta1.Eviction" + "$ref": "#/definitions/io.k8s.api.policy.v1.Eviction" } } ], @@ -25143,19 +25143,19 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/io.k8s.api.policy.v1beta1.Eviction" + "$ref": "#/definitions/io.k8s.api.policy.v1.Eviction" } }, "201": { "description": "Created", "schema": { - "$ref": "#/definitions/io.k8s.api.policy.v1beta1.Eviction" + "$ref": "#/definitions/io.k8s.api.policy.v1.Eviction" } }, "202": { "description": "Accepted", "schema": { - "$ref": "#/definitions/io.k8s.api.policy.v1beta1.Eviction" + "$ref": "#/definitions/io.k8s.api.policy.v1.Eviction" } }, "401": { @@ -25172,7 +25172,7 @@ "x-kubernetes-group-version-kind": { "group": "policy", "kind": "Eviction", - "version": "v1beta1" + "version": "v1" } } }, diff --git a/pkg/apis/policy/v1/zz_generated.conversion.go b/pkg/apis/policy/v1/zz_generated.conversion.go index d9d5eb840a4..21e6554ca38 100644 --- a/pkg/apis/policy/v1/zz_generated.conversion.go +++ b/pkg/apis/policy/v1/zz_generated.conversion.go @@ -38,6 +38,16 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1.Eviction)(nil), (*policy.Eviction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Eviction_To_policy_Eviction(a.(*v1.Eviction), b.(*policy.Eviction), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*policy.Eviction)(nil), (*v1.Eviction)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_policy_Eviction_To_v1_Eviction(a.(*policy.Eviction), b.(*v1.Eviction), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*policy.PodDisruptionBudget)(nil), (*v1.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget(a.(*policy.PodDisruptionBudget), b.(*v1.PodDisruptionBudget), scope) }); err != nil { @@ -81,6 +91,28 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v1_Eviction_To_policy_Eviction(in *v1.Eviction, out *policy.Eviction, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.DeleteOptions = (*metav1.DeleteOptions)(unsafe.Pointer(in.DeleteOptions)) + return nil +} + +// Convert_v1_Eviction_To_policy_Eviction is an autogenerated conversion function. +func Convert_v1_Eviction_To_policy_Eviction(in *v1.Eviction, out *policy.Eviction, s conversion.Scope) error { + return autoConvert_v1_Eviction_To_policy_Eviction(in, out, s) +} + +func autoConvert_policy_Eviction_To_v1_Eviction(in *policy.Eviction, out *v1.Eviction, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + out.DeleteOptions = (*metav1.DeleteOptions)(unsafe.Pointer(in.DeleteOptions)) + return nil +} + +// Convert_policy_Eviction_To_v1_Eviction is an autogenerated conversion function. +func Convert_policy_Eviction_To_v1_Eviction(in *policy.Eviction, out *v1.Eviction, s conversion.Scope) error { + return autoConvert_policy_Eviction_To_v1_Eviction(in, out, s) +} + func autoConvert_v1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *v1.PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(&in.Spec, &out.Spec, s); err != nil { diff --git a/staging/src/k8s.io/api/policy/v1/generated.pb.go b/staging/src/k8s.io/api/policy/v1/generated.pb.go index 9a9f73c124d..183db076aa5 100644 --- a/staging/src/k8s.io/api/policy/v1/generated.pb.go +++ b/staging/src/k8s.io/api/policy/v1/generated.pb.go @@ -47,10 +47,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *Eviction) Reset() { *m = Eviction{} } +func (*Eviction) ProtoMessage() {} +func (*Eviction) Descriptor() ([]byte, []int) { + return fileDescriptor_2d50488813b2d18e, []int{0} +} +func (m *Eviction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Eviction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *Eviction) XXX_Merge(src proto.Message) { + xxx_messageInfo_Eviction.Merge(m, src) +} +func (m *Eviction) XXX_Size() int { + return m.Size() +} +func (m *Eviction) XXX_DiscardUnknown() { + xxx_messageInfo_Eviction.DiscardUnknown(m) +} + +var xxx_messageInfo_Eviction proto.InternalMessageInfo + func (m *PodDisruptionBudget) Reset() { *m = PodDisruptionBudget{} } func (*PodDisruptionBudget) ProtoMessage() {} func (*PodDisruptionBudget) Descriptor() ([]byte, []int) { - return fileDescriptor_2d50488813b2d18e, []int{0} + return fileDescriptor_2d50488813b2d18e, []int{1} } func (m *PodDisruptionBudget) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,7 +106,7 @@ var xxx_messageInfo_PodDisruptionBudget proto.InternalMessageInfo func (m *PodDisruptionBudgetList) Reset() { *m = PodDisruptionBudgetList{} } func (*PodDisruptionBudgetList) ProtoMessage() {} func (*PodDisruptionBudgetList) Descriptor() ([]byte, []int) { - return fileDescriptor_2d50488813b2d18e, []int{1} + return fileDescriptor_2d50488813b2d18e, []int{2} } func (m *PodDisruptionBudgetList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +134,7 @@ var xxx_messageInfo_PodDisruptionBudgetList proto.InternalMessageInfo func (m *PodDisruptionBudgetSpec) Reset() { *m = PodDisruptionBudgetSpec{} } func (*PodDisruptionBudgetSpec) ProtoMessage() {} func (*PodDisruptionBudgetSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_2d50488813b2d18e, []int{2} + return fileDescriptor_2d50488813b2d18e, []int{3} } func (m *PodDisruptionBudgetSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -134,7 +162,7 @@ var xxx_messageInfo_PodDisruptionBudgetSpec proto.InternalMessageInfo func (m *PodDisruptionBudgetStatus) Reset() { *m = PodDisruptionBudgetStatus{} } func (*PodDisruptionBudgetStatus) ProtoMessage() {} func (*PodDisruptionBudgetStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2d50488813b2d18e, []int{3} + return fileDescriptor_2d50488813b2d18e, []int{4} } func (m *PodDisruptionBudgetStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -160,6 +188,7 @@ func (m *PodDisruptionBudgetStatus) XXX_DiscardUnknown() { var xxx_messageInfo_PodDisruptionBudgetStatus proto.InternalMessageInfo func init() { + proto.RegisterType((*Eviction)(nil), "k8s.io.api.policy.v1.Eviction") proto.RegisterType((*PodDisruptionBudget)(nil), "k8s.io.api.policy.v1.PodDisruptionBudget") proto.RegisterType((*PodDisruptionBudgetList)(nil), "k8s.io.api.policy.v1.PodDisruptionBudgetList") proto.RegisterType((*PodDisruptionBudgetSpec)(nil), "k8s.io.api.policy.v1.PodDisruptionBudgetSpec") @@ -172,55 +201,103 @@ func init() { } var fileDescriptor_2d50488813b2d18e = []byte{ - // 766 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xdf, 0x6e, 0xe3, 0x44, - 0x14, 0xc6, 0xe3, 0xa4, 0x29, 0x65, 0x36, 0x8d, 0xaa, 0x61, 0x81, 0x90, 0x0b, 0x77, 0xd5, 0xab, - 0x82, 0xb4, 0x63, 0xba, 0x8b, 0x50, 0x85, 0x04, 0x62, 0xbd, 0x59, 0xc1, 0x22, 0x4a, 0x56, 0x53, - 0x10, 0x12, 0x02, 0x89, 0x89, 0x7d, 0xd6, 0x19, 0x62, 0x7b, 0xac, 0x99, 0xb1, 0xd9, 0x5c, 0xc1, - 0x23, 0xf0, 0x0a, 0x3c, 0x0a, 0x57, 0xf4, 0x0a, 0xed, 0xe5, 0x5e, 0x45, 0xd4, 0xbc, 0x08, 0xf2, - 0xd8, 0xf9, 0xe3, 0x24, 0x55, 0x03, 0x77, 0x99, 0x39, 0xe7, 0xfb, 0x9d, 0x39, 0xdf, 0x39, 0x0e, - 0xfa, 0x78, 0x72, 0xae, 0x08, 0x17, 0xce, 0x24, 0x1d, 0x81, 0x8c, 0x41, 0x83, 0x72, 0x32, 0x88, - 0x7d, 0x21, 0x9d, 0x2a, 0xc0, 0x12, 0xee, 0x24, 0x22, 0xe4, 0xde, 0xd4, 0xc9, 0xce, 0x9c, 0x00, - 0x62, 0x90, 0x4c, 0x83, 0x4f, 0x12, 0x29, 0xb4, 0xc0, 0x77, 0xcb, 0x2c, 0xc2, 0x12, 0x4e, 0xca, - 0x2c, 0x92, 0x9d, 0xf5, 0xef, 0x07, 0x5c, 0x8f, 0xd3, 0x11, 0xf1, 0x44, 0xe4, 0x04, 0x22, 0x10, - 0x8e, 0x49, 0x1e, 0xa5, 0xcf, 0xcd, 0xc9, 0x1c, 0xcc, 0xaf, 0x12, 0xd2, 0xff, 0x60, 0x59, 0x2a, - 0x62, 0xde, 0x98, 0xc7, 0x20, 0xa7, 0x4e, 0x32, 0x09, 0x8a, 0x0b, 0xe5, 0x44, 0xa0, 0xd9, 0x96, - 0xd2, 0x7d, 0xe7, 0x26, 0x95, 0x4c, 0x63, 0xcd, 0x23, 0xd8, 0x10, 0x7c, 0x78, 0x9b, 0x40, 0x79, - 0x63, 0x88, 0xd8, 0x86, 0xee, 0xe1, 0x4d, 0xba, 0x54, 0xf3, 0xd0, 0xe1, 0xb1, 0x56, 0x5a, 0xae, - 0x8b, 0x4e, 0x7e, 0x6f, 0xa2, 0x37, 0x9e, 0x09, 0x7f, 0xc0, 0x95, 0x4c, 0x13, 0xcd, 0x45, 0xec, - 0xa6, 0x7e, 0x00, 0x1a, 0xff, 0x88, 0x0e, 0x8a, 0x86, 0x7c, 0xa6, 0x59, 0xcf, 0xba, 0x67, 0x9d, - 0xde, 0x79, 0xf0, 0x3e, 0x59, 0x7a, 0xb8, 0xe0, 0x93, 0x64, 0x12, 0x14, 0x17, 0x8a, 0x14, 0xd9, - 0x24, 0x3b, 0x23, 0xc3, 0xd1, 0x4f, 0xe0, 0xe9, 0x0b, 0xd0, 0xcc, 0xc5, 0x57, 0xb3, 0xe3, 0x46, - 0x3e, 0x3b, 0x46, 0xcb, 0x3b, 0xba, 0xa0, 0xe2, 0x21, 0xda, 0x53, 0x09, 0x78, 0xbd, 0xa6, 0xa1, - 0xdf, 0x27, 0xdb, 0x26, 0x44, 0xb6, 0x3c, 0xed, 0x32, 0x01, 0xcf, 0xed, 0x54, 0xe8, 0xbd, 0xe2, - 0x44, 0x0d, 0x08, 0x7f, 0x8b, 0xf6, 0x95, 0x66, 0x3a, 0x55, 0xbd, 0x96, 0x41, 0x3a, 0xbb, 0x23, - 0x8d, 0xcc, 0xed, 0x56, 0xd0, 0xfd, 0xf2, 0x4c, 0x2b, 0xdc, 0xc9, 0x9f, 0x16, 0x7a, 0x7b, 0x8b, - 0xea, 0x4b, 0xae, 0x34, 0xfe, 0x7e, 0xc3, 0x27, 0xb2, 0x9b, 0x4f, 0x85, 0xda, 0xb8, 0x74, 0x54, - 0x55, 0x3d, 0x98, 0xdf, 0xac, 0x78, 0xf4, 0x15, 0x6a, 0x73, 0x0d, 0x91, 0xea, 0x35, 0xef, 0xb5, - 0x4e, 0xef, 0x3c, 0x78, 0x77, 0xe7, 0x8e, 0xdc, 0xc3, 0x8a, 0xda, 0x7e, 0x5a, 0xe8, 0x69, 0x89, - 0x39, 0xf9, 0xab, 0xb9, 0xb5, 0x93, 0xc2, 0x44, 0xfc, 0x1c, 0x75, 0x22, 0x1e, 0x3f, 0xca, 0x18, - 0x0f, 0xd9, 0x28, 0x84, 0x5b, 0xa7, 0x5e, 0x6c, 0x15, 0x29, 0xb7, 0x8a, 0x3c, 0x8d, 0xf5, 0x50, - 0x5e, 0x6a, 0xc9, 0xe3, 0xc0, 0x3d, 0xca, 0x67, 0xc7, 0x9d, 0x8b, 0x15, 0x12, 0xad, 0x71, 0xf1, - 0x0f, 0xe8, 0x40, 0x41, 0x08, 0x9e, 0x16, 0xb2, 0x9a, 0xfd, 0xc3, 0x1d, 0x1d, 0x63, 0x23, 0x08, - 0x2f, 0x2b, 0xa9, 0xdb, 0x29, 0x2c, 0x9b, 0x9f, 0xe8, 0x02, 0x89, 0x43, 0xd4, 0x8d, 0xd8, 0x8b, - 0x6f, 0x62, 0xb6, 0x68, 0xa4, 0xf5, 0x3f, 0x1b, 0xc1, 0xf9, 0xec, 0xb8, 0x7b, 0x51, 0x63, 0xd1, - 0x35, 0xf6, 0xc9, 0x1f, 0x6d, 0xf4, 0xce, 0x8d, 0x0b, 0x85, 0xbf, 0x40, 0x58, 0x8c, 0x14, 0xc8, - 0x0c, 0xfc, 0xcf, 0xca, 0xef, 0x8e, 0x8b, 0xd8, 0x18, 0xdb, 0x72, 0xfb, 0xd5, 0x80, 0xf0, 0x70, - 0x23, 0x83, 0x6e, 0x51, 0xe1, 0x5f, 0xd0, 0xa1, 0x5f, 0x56, 0x01, 0xff, 0x99, 0xf0, 0xe7, 0x2b, - 0xe1, 0xfe, 0xc7, 0x25, 0x27, 0x83, 0x55, 0xc8, 0x93, 0x58, 0xcb, 0xa9, 0xfb, 0x66, 0xf5, 0x94, - 0xc3, 0x5a, 0x8c, 0xd6, 0xeb, 0x15, 0xcd, 0xf8, 0x0b, 0xa4, 0x7a, 0x14, 0x86, 0xe2, 0x67, 0xf0, - 0x8d, 0xb9, 0xed, 0x65, 0x33, 0x83, 0x8d, 0x0c, 0xba, 0x45, 0x85, 0x3f, 0x41, 0x5d, 0x2f, 0x95, - 0x12, 0x62, 0xfd, 0x39, 0xb0, 0x50, 0x8f, 0xa7, 0xbd, 0x3d, 0xc3, 0x79, 0xab, 0xe2, 0x74, 0x1f, - 0xd7, 0xa2, 0x74, 0x2d, 0xbb, 0xd0, 0xfb, 0xa0, 0xb8, 0x04, 0x7f, 0xae, 0x6f, 0xd7, 0xf5, 0x83, - 0x5a, 0x94, 0xae, 0x65, 0xe3, 0x73, 0xd4, 0x81, 0x17, 0x09, 0x78, 0x73, 0x2f, 0xf7, 0x8d, 0xfa, - 0x6e, 0xa5, 0xee, 0x3c, 0x59, 0x89, 0xd1, 0x5a, 0x26, 0xf6, 0x10, 0xf2, 0x44, 0xec, 0x73, 0xd3, - 0x4e, 0xef, 0x35, 0x33, 0x03, 0x67, 0xb7, 0xfd, 0x7d, 0x3c, 0xd7, 0x2d, 0xff, 0x18, 0x17, 0x57, - 0x8a, 0xae, 0x60, 0xfb, 0x21, 0xc2, 0x9b, 0x63, 0xc2, 0x47, 0xa8, 0x35, 0x81, 0xa9, 0x59, 0x9f, - 0xd7, 0x69, 0xf1, 0x13, 0x7f, 0x8a, 0xda, 0x19, 0x0b, 0x53, 0xa8, 0xbe, 0xa3, 0xf7, 0x76, 0x7b, - 0xc7, 0xd7, 0x3c, 0x02, 0x5a, 0x0a, 0x3f, 0x6a, 0x9e, 0x5b, 0xee, 0xe9, 0xd5, 0xb5, 0xdd, 0x78, - 0x79, 0x6d, 0x37, 0x5e, 0x5d, 0xdb, 0x8d, 0x5f, 0x73, 0xdb, 0xba, 0xca, 0x6d, 0xeb, 0x65, 0x6e, - 0x5b, 0xaf, 0x72, 0xdb, 0xfa, 0x3b, 0xb7, 0xad, 0xdf, 0xfe, 0xb1, 0x1b, 0xdf, 0x35, 0xb3, 0xb3, - 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xca, 0x04, 0x93, 0xc0, 0x85, 0x07, 0x00, 0x00, + // 805 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xdf, 0x8e, 0xdb, 0x44, + 0x14, 0xc6, 0xe3, 0x64, 0xb3, 0x2c, 0xd3, 0x24, 0x5a, 0x86, 0x02, 0x4b, 0x2e, 0x1c, 0x94, 0xab, + 0x05, 0xa9, 0x63, 0xb6, 0x45, 0x68, 0x85, 0x04, 0xa2, 0x6e, 0x56, 0x50, 0xd4, 0x25, 0xd5, 0x2c, + 0x08, 0x09, 0x81, 0xc4, 0xc4, 0x3e, 0xcd, 0x0e, 0xb1, 0x3d, 0xd6, 0xcc, 0xd8, 0x34, 0x57, 0xf0, + 0x08, 0xbc, 0x02, 0x8f, 0xc2, 0x15, 0x7b, 0x85, 0x7a, 0x59, 0x71, 0x11, 0xb1, 0xe6, 0x45, 0x90, + 0xc7, 0xce, 0x1f, 0x27, 0x59, 0x35, 0xe5, 0x82, 0x3b, 0xcf, 0x99, 0xf3, 0xfd, 0x8e, 0xcf, 0x37, + 0x67, 0x06, 0x7d, 0x3c, 0x39, 0x55, 0x84, 0x0b, 0x67, 0x92, 0x8c, 0x40, 0x46, 0xa0, 0x41, 0x39, + 0x29, 0x44, 0xbe, 0x90, 0x4e, 0xb9, 0xc1, 0x62, 0xee, 0xc4, 0x22, 0xe0, 0xde, 0xd4, 0x49, 0x4f, + 0x9c, 0x31, 0x44, 0x20, 0x99, 0x06, 0x9f, 0xc4, 0x52, 0x68, 0x81, 0x6f, 0x17, 0x59, 0x84, 0xc5, + 0x9c, 0x14, 0x59, 0x24, 0x3d, 0xe9, 0xde, 0x19, 0x73, 0x7d, 0x99, 0x8c, 0x88, 0x27, 0x42, 0x67, + 0x2c, 0xc6, 0xc2, 0x31, 0xc9, 0xa3, 0xe4, 0x89, 0x59, 0x99, 0x85, 0xf9, 0x2a, 0x20, 0xdd, 0x0f, + 0x96, 0xa5, 0x42, 0xe6, 0x5d, 0xf2, 0x08, 0xe4, 0xd4, 0x89, 0x27, 0xe3, 0x3c, 0xa0, 0x9c, 0x10, + 0x34, 0xdb, 0x52, 0xba, 0xeb, 0xdc, 0xa4, 0x92, 0x49, 0xa4, 0x79, 0x08, 0x1b, 0x82, 0x0f, 0x5f, + 0x24, 0x50, 0xde, 0x25, 0x84, 0x6c, 0x43, 0x77, 0xef, 0x26, 0x5d, 0xa2, 0x79, 0xe0, 0xf0, 0x48, + 0x2b, 0x2d, 0xd7, 0x45, 0xfd, 0xbf, 0x2c, 0x74, 0x70, 0x96, 0x72, 0x4f, 0x73, 0x11, 0xe1, 0x1f, + 0xd0, 0x41, 0xde, 0x85, 0xcf, 0x34, 0x3b, 0xb2, 0xde, 0xb1, 0x8e, 0x6f, 0xdd, 0x7d, 0x9f, 0x2c, + 0x8d, 0x5b, 0x40, 0x49, 0x3c, 0x19, 0xe7, 0x01, 0x45, 0xf2, 0x6c, 0x92, 0x9e, 0x90, 0xe1, 0xe8, + 0x47, 0xf0, 0xf4, 0x39, 0x68, 0xe6, 0xe2, 0xab, 0x59, 0xaf, 0x96, 0xcd, 0x7a, 0x68, 0x19, 0xa3, + 0x0b, 0x2a, 0x0e, 0x50, 0xdb, 0x87, 0x00, 0x34, 0x0c, 0xe3, 0xbc, 0xa2, 0x3a, 0xaa, 0x9b, 0x32, + 0xf7, 0x76, 0x2b, 0x33, 0x58, 0x95, 0xba, 0xaf, 0x65, 0xb3, 0x5e, 0xbb, 0x12, 0xa2, 0x55, 0x78, + 0xff, 0xb7, 0x3a, 0x7a, 0xfd, 0xb1, 0xf0, 0x07, 0x5c, 0xc9, 0xc4, 0x84, 0xdc, 0xc4, 0x1f, 0x83, + 0xfe, 0x1f, 0xfa, 0x1c, 0xa2, 0x3d, 0x15, 0x83, 0x57, 0xb6, 0x77, 0x87, 0x6c, 0x1b, 0x3f, 0xb2, + 0xe5, 0xd7, 0x2e, 0x62, 0xf0, 0xdc, 0x56, 0x89, 0xde, 0xcb, 0x57, 0xd4, 0x80, 0xf0, 0x37, 0x68, + 0x5f, 0x69, 0xa6, 0x13, 0x75, 0xd4, 0x30, 0x48, 0x67, 0x77, 0xa4, 0x91, 0xb9, 0x9d, 0x12, 0xba, + 0x5f, 0xac, 0x69, 0x89, 0xeb, 0xff, 0x61, 0xa1, 0xb7, 0xb6, 0xa8, 0x1e, 0x71, 0xa5, 0xf1, 0x77, + 0x1b, 0x3e, 0x91, 0xdd, 0x7c, 0xca, 0xd5, 0xc6, 0xa5, 0xc3, 0xb2, 0xea, 0xc1, 0x3c, 0xb2, 0xe2, + 0xd1, 0x97, 0xa8, 0xc9, 0x35, 0x84, 0xf9, 0x0c, 0x34, 0x8e, 0x6f, 0xdd, 0x7d, 0x77, 0xe7, 0x8e, + 0xdc, 0x76, 0x49, 0x6d, 0x3e, 0xcc, 0xf5, 0xb4, 0xc0, 0xf4, 0xff, 0xac, 0x6f, 0xed, 0x24, 0x37, + 0x11, 0x3f, 0x41, 0xad, 0x90, 0x47, 0xf7, 0x53, 0xc6, 0x03, 0x36, 0x0a, 0xe0, 0x85, 0xa7, 0x9e, + 0x5f, 0x19, 0x52, 0x5c, 0x19, 0xf2, 0x30, 0xd2, 0x43, 0x79, 0xa1, 0x25, 0x8f, 0xc6, 0xee, 0x61, + 0x36, 0xeb, 0xb5, 0xce, 0x57, 0x48, 0xb4, 0xc2, 0xc5, 0xdf, 0xa3, 0x03, 0x05, 0x01, 0x78, 0x5a, + 0xc8, 0x97, 0x1b, 0xed, 0x47, 0x6c, 0x04, 0xc1, 0x45, 0x29, 0x75, 0x5b, 0xb9, 0x65, 0xf3, 0x15, + 0x5d, 0x20, 0x71, 0x80, 0x3a, 0x21, 0x7b, 0xfa, 0x75, 0xc4, 0x16, 0x8d, 0x34, 0xfe, 0x63, 0x23, + 0x38, 0x9b, 0xf5, 0x3a, 0xe7, 0x15, 0x16, 0x5d, 0x63, 0xf7, 0x7f, 0x6f, 0xa2, 0xb7, 0x6f, 0x1c, + 0x28, 0xfc, 0x05, 0xc2, 0x62, 0xa4, 0x40, 0xa6, 0xe0, 0x7f, 0x56, 0x3c, 0x2a, 0x5c, 0x44, 0xc6, + 0xd8, 0x86, 0xdb, 0x2d, 0x0f, 0x08, 0x0f, 0x37, 0x32, 0xe8, 0x16, 0x15, 0xfe, 0x19, 0xb5, 0xfd, + 0xa2, 0x0a, 0xf8, 0x8f, 0x85, 0x3f, 0x1f, 0x09, 0xf7, 0x25, 0x87, 0x9c, 0x0c, 0x56, 0x21, 0x67, + 0x91, 0x96, 0x53, 0xf7, 0x8d, 0xf2, 0x57, 0xda, 0x95, 0x3d, 0x5a, 0xad, 0x97, 0x37, 0xe3, 0x2f, + 0x90, 0xea, 0x7e, 0x10, 0x88, 0x9f, 0xc0, 0x37, 0xe6, 0x36, 0x97, 0xcd, 0x0c, 0x36, 0x32, 0xe8, + 0x16, 0x15, 0xfe, 0x04, 0x75, 0xbc, 0x44, 0x4a, 0x88, 0xf4, 0xe7, 0xc0, 0x02, 0x7d, 0x39, 0x3d, + 0xda, 0x33, 0x9c, 0x37, 0x4b, 0x4e, 0xe7, 0x41, 0x65, 0x97, 0xae, 0x65, 0xe7, 0x7a, 0x1f, 0x14, + 0x97, 0xe0, 0xcf, 0xf5, 0xcd, 0xaa, 0x7e, 0x50, 0xd9, 0xa5, 0x6b, 0xd9, 0xf8, 0x14, 0xb5, 0xe0, + 0x69, 0x0c, 0xde, 0xdc, 0xcb, 0x7d, 0xa3, 0xbe, 0x5d, 0xaa, 0x5b, 0x67, 0x2b, 0x7b, 0xb4, 0x92, + 0x89, 0x3d, 0x84, 0x3c, 0x11, 0xf9, 0xbc, 0x78, 0x9a, 0x5f, 0x31, 0x67, 0xe0, 0xec, 0x36, 0xbf, + 0x0f, 0xe6, 0xba, 0xe5, 0xc3, 0xb8, 0x08, 0x29, 0xba, 0x82, 0xed, 0x06, 0x08, 0x6f, 0x1e, 0x13, + 0x3e, 0x44, 0x8d, 0x09, 0x4c, 0xcd, 0xf8, 0xbc, 0x4a, 0xf3, 0x4f, 0xfc, 0x29, 0x6a, 0xa6, 0x2c, + 0x48, 0xa0, 0xbc, 0x47, 0xef, 0xed, 0xf6, 0x1f, 0x5f, 0xf1, 0x10, 0x68, 0x21, 0xfc, 0xa8, 0x7e, + 0x6a, 0xb9, 0xc7, 0x57, 0xd7, 0x76, 0xed, 0xd9, 0xb5, 0x5d, 0x7b, 0x7e, 0x6d, 0xd7, 0x7e, 0xc9, + 0x6c, 0xeb, 0x2a, 0xb3, 0xad, 0x67, 0x99, 0x6d, 0x3d, 0xcf, 0x6c, 0xeb, 0xef, 0xcc, 0xb6, 0x7e, + 0xfd, 0xc7, 0xae, 0x7d, 0x5b, 0x4f, 0x4f, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xce, 0x1b, 0x9d, + 0x9f, 0x62, 0x08, 0x00, 0x00, +} + +func (m *Eviction) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Eviction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Eviction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DeleteOptions != nil { + { + size, err := m.DeleteOptions.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + { + size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *PodDisruptionBudget) Marshal() (dAtA []byte, err error) { @@ -474,6 +551,21 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *Eviction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.DeleteOptions != nil { + l = m.DeleteOptions.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + func (m *PodDisruptionBudget) Size() (n int) { if m == nil { return 0 @@ -562,6 +654,17 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *Eviction) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Eviction{`, + `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `DeleteOptions:` + strings.Replace(fmt.Sprintf("%v", this.DeleteOptions), "DeleteOptions", "v1.DeleteOptions", 1) + `,`, + `}`, + }, "") + return s +} func (this *PodDisruptionBudget) String() string { if this == nil { return "nil" @@ -641,6 +744,125 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *Eviction) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Eviction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Eviction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DeleteOptions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.DeleteOptions == nil { + m.DeleteOptions = &v1.DeleteOptions{} + } + if err := m.DeleteOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PodDisruptionBudget) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/staging/src/k8s.io/api/policy/v1/generated.proto b/staging/src/k8s.io/api/policy/v1/generated.proto index f57514112a0..5b798423564 100644 --- a/staging/src/k8s.io/api/policy/v1/generated.proto +++ b/staging/src/k8s.io/api/policy/v1/generated.proto @@ -29,6 +29,19 @@ import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1"; +// Eviction evicts a pod from its node subject to certain policies and safety constraints. +// This is a subresource of Pod. A request to cause such an eviction is +// created by POSTing to .../pods//evictions. +message Eviction { + // ObjectMeta describes the pod that is being evicted. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // DeleteOptions may be provided + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.DeleteOptions deleteOptions = 2; +} + // PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods message PodDisruptionBudget { // Standard object's metadata. diff --git a/staging/src/k8s.io/api/policy/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/policy/v1/types_swagger_doc_generated.go index 0b80a1dccf1..3208392e880 100644 --- a/staging/src/k8s.io/api/policy/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/policy/v1/types_swagger_doc_generated.go @@ -27,6 +27,16 @@ package v1 // Those methods can be generated by using hack/update-generated-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_Eviction = map[string]string{ + "": "Eviction evicts a pod from its node subject to certain policies and safety constraints. This is a subresource of Pod. A request to cause such an eviction is created by POSTing to .../pods//evictions.", + "metadata": "ObjectMeta describes the pod that is being evicted.", + "deleteOptions": "DeleteOptions may be provided", +} + +func (Eviction) SwaggerDoc() map[string]string { + return map_Eviction +} + var map_PodDisruptionBudget = map[string]string{ "": "PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods", "metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", diff --git a/staging/src/k8s.io/api/policy/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/policy/v1/zz_generated.deepcopy.go index 78c0adbd705..9b7aac2f198 100644 --- a/staging/src/k8s.io/api/policy/v1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/policy/v1/zz_generated.deepcopy.go @@ -26,6 +26,37 @@ import ( intstr "k8s.io/apimachinery/pkg/util/intstr" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Eviction) DeepCopyInto(out *Eviction) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.DeleteOptions != nil { + in, out := &in.DeleteOptions, &out.DeleteOptions + *out = new(metav1.DeleteOptions) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Eviction. +func (in *Eviction) DeepCopy() *Eviction { + if in == nil { + return nil + } + out := new(Eviction) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Eviction) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodDisruptionBudget) DeepCopyInto(out *PodDisruptionBudget) { *out = *in diff --git a/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.json b/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.json new file mode 100644 index 00000000000..b48ebc6dd8e --- /dev/null +++ b/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.json @@ -0,0 +1,55 @@ +{ + "kind": "Eviction", + "apiVersion": "policy/v1", + "metadata": { + "name": "2", + "generateName": "3", + "namespace": "4", + "selfLink": "5", + "uid": "7", + "resourceVersion": "11042405498087606203", + "generation": 8071137005907523419, + "creationTimestamp": null, + "deletionGracePeriodSeconds": -4955867275792137171, + "labels": { + "7": "8" + }, + "annotations": { + "9": "10" + }, + "ownerReferences": [ + { + "apiVersion": "11", + "kind": "12", + "name": "13", + "uid": "Dz廔ȇ{sŊƏp", + "controller": false, + "blockOwnerDeletion": true + } + ], + "finalizers": [ + "14" + ], + "clusterName": "15", + "managedFields": [ + { + "manager": "16", + "operation": "鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć]", + "apiVersion": "17", + "fieldsType": "18" + } + ] + }, + "deleteOptions": { + "gracePeriodSeconds": 3850803321873644574, + "preconditions": { + "uid": "枊a8衍`Ĩɘ.蘯6ċV夸eɑeʤ脽ě", + "resourceVersion": "19" + }, + "orphanDependents": true, + "propagationPolicy": "蓏Ŋ", + "dryRun": [ + "20" + ] + } +} \ No newline at end of file diff --git a/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.pb b/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.pb new file mode 100644 index 0000000000000000000000000000000000000000..1d1917ba1aceefbb43e5c39f63a153ef12937c44 GIT binary patch literal 274 zcmV+t0qy>4ICB6B6$%M(Z)|B}c`tS`5(q_hX=8M0Z*CIs0Sc)B3IQ?_0W%r_G$H{t zDgie#6frR{G%_?WH8eRmFgQ0hFg7wUGdSDsg4KbGoPlsc08p)nwS$G9&YZgeS_TRM zHxdCjVh0KVIT8XfFlrzQ0x>cg0x>fp4n%t8yOhX>dvnE##*c6+0x>Z#05}110x>jt z0x>m;0WS&yF*Xt*>5z)$l#1!2nZ=$hRpp$t!?$5C$&`KOk%1`YxtGL-T^a&0H!=b- zI1)k#p7^k#fTy##H4-TbBj%opVL0fajbOy6$(Szan6Ea(i&o{NxMj(aWy+-JguTR@ Y5&|(f7y%*$=#!7diYfv!Fd6_N07-da_W%F@ literal 0 HcmV?d00001 diff --git a/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.yaml b/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.yaml new file mode 100644 index 00000000000..d5a72ba4826 --- /dev/null +++ b/staging/src/k8s.io/api/testdata/HEAD/policy.v1.Eviction.yaml @@ -0,0 +1,40 @@ +apiVersion: policy/v1 +deleteOptions: + dryRun: + - "20" + gracePeriodSeconds: 3850803321873644574 + orphanDependents: true + preconditions: + resourceVersion: "19" + uid: 枊a8衍`Ĩɘ.蘯6ċV夸eɑeʤ脽ě + propagationPolicy: 蓏Ŋ +kind: Eviction +metadata: + annotations: + "9": "10" + clusterName: "15" + creationTimestamp: null + deletionGracePeriodSeconds: -4955867275792137171 + finalizers: + - "14" + generateName: "3" + generation: 8071137005907523419 + labels: + "7": "8" + managedFields: + - apiVersion: "17" + fieldsType: "18" + manager: "16" + operation: 鐊唊飙Ş-U圴÷a/ɔ}摁(湗Ć] + name: "2" + namespace: "4" + ownerReferences: + - apiVersion: "11" + blockOwnerDeletion: true + controller: false + kind: "12" + name: "13" + uid: Dz廔ȇ{sŊƏp + resourceVersion: "11042405498087606203" + selfLink: "5" + uid: "7" diff --git a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go index 0683000968e..2b92c17b3c8 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go @@ -8984,6 +8984,22 @@ var schemaYAML = typed.YAMLObject(`types: elementType: namedType: io.k8s.api.core.v1.Toleration elementRelationship: atomic +- name: io.k8s.api.policy.v1.Eviction + map: + fields: + - name: apiVersion + type: + scalar: string + - name: deleteOptions + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} - name: io.k8s.api.policy.v1.PodDisruptionBudget map: fields: diff --git a/staging/src/k8s.io/client-go/applyconfigurations/policy/v1/eviction.go b/staging/src/k8s.io/client-go/applyconfigurations/policy/v1/eviction.go new file mode 100644 index 00000000000..a725a9533b3 --- /dev/null +++ b/staging/src/k8s.io/client-go/applyconfigurations/policy/v1/eviction.go @@ -0,0 +1,256 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + policyv1 "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + internal "k8s.io/client-go/applyconfigurations/internal" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// EvictionApplyConfiguration represents an declarative configuration of the Eviction type for use +// with apply. +type EvictionApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + DeleteOptions *v1.DeleteOptionsApplyConfiguration `json:"deleteOptions,omitempty"` +} + +// Eviction constructs an declarative configuration of the Eviction type for use with +// apply. +func Eviction(name, namespace string) *EvictionApplyConfiguration { + b := &EvictionApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("Eviction") + b.WithAPIVersion("policy/v1") + return b +} + +// ExtractEviction extracts the applied configuration owned by fieldManager from +// eviction. If no managedFields are found in eviction for fieldManager, a +// EvictionApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. Is is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// eviction must be a unmodified Eviction API object that was retrieved from the Kubernetes API. +// ExtractEviction provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractEviction(eviction *policyv1.Eviction, fieldManager string) (*EvictionApplyConfiguration, error) { + b := &EvictionApplyConfiguration{} + err := managedfields.ExtractInto(eviction, internal.Parser().Type("io.k8s.api.policy.v1.Eviction"), fieldManager, b) + if err != nil { + return nil, err + } + b.WithName(eviction.Name) + b.WithNamespace(eviction.Namespace) + + b.WithKind("Eviction") + b.WithAPIVersion("policy/v1") + return b, nil +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithKind(value string) *EvictionApplyConfiguration { + b.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithAPIVersion(value string) *EvictionApplyConfiguration { + b.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithName(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithGenerateName(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithNamespace(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Namespace = &value + return b +} + +// WithSelfLink sets the SelfLink field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the SelfLink field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithSelfLink(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.SelfLink = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithUID(value types.UID) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithResourceVersion(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithGeneration(value int64) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithCreationTimestamp(value metav1.Time) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *EvictionApplyConfiguration) WithLabels(entries map[string]string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Labels == nil && len(entries) > 0 { + b.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *EvictionApplyConfiguration) WithAnnotations(entries map[string]string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.Annotations == nil && len(entries) > 0 { + b.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *EvictionApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.OwnerReferences = append(b.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *EvictionApplyConfiguration) WithFinalizers(values ...string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.Finalizers = append(b.Finalizers, values[i]) + } + return b +} + +// WithClusterName sets the ClusterName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ClusterName field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithClusterName(value string) *EvictionApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ClusterName = &value + return b +} + +func (b *EvictionApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithDeleteOptions sets the DeleteOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeleteOptions field is set to the value of the last call. +func (b *EvictionApplyConfiguration) WithDeleteOptions(value *v1.DeleteOptionsApplyConfiguration) *EvictionApplyConfiguration { + b.DeleteOptions = value + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/utils.go b/staging/src/k8s.io/client-go/applyconfigurations/utils.go index d4ac78a1b7e..50103b5f565 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/utils.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/utils.go @@ -1139,6 +1139,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &applyconfigurationsnodev1beta1.SchedulingApplyConfiguration{} // Group=policy, Version=v1 + case policyv1.SchemeGroupVersion.WithKind("Eviction"): + return &applyconfigurationspolicyv1.EvictionApplyConfiguration{} case policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget"): return &applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration{} case policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudgetSpec"): diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction.go new file mode 100644 index 00000000000..cd1aac9c29a --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/eviction.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + rest "k8s.io/client-go/rest" +) + +// EvictionsGetter has a method to return a EvictionInterface. +// A group's client should implement this interface. +type EvictionsGetter interface { + Evictions(namespace string) EvictionInterface +} + +// EvictionInterface has methods to work with Eviction resources. +type EvictionInterface interface { + EvictionExpansion +} + +// evictions implements EvictionInterface +type evictions struct { + client rest.Interface + ns string +} + +// newEvictions returns a Evictions +func newEvictions(c *PolicyV1Client, namespace string) *evictions { + return &evictions{ + client: c.RESTClient(), + ns: namespace, + } +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go new file mode 100644 index 00000000000..a579067ce83 --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_eviction.go @@ -0,0 +1,25 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +// FakeEvictions implements EvictionInterface +type FakeEvictions struct { + Fake *FakePolicyV1 + ns string +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go index ba0f039b211..d5bb3d549ae 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/fake/fake_policy_client.go @@ -28,6 +28,10 @@ type FakePolicyV1 struct { *testing.Fake } +func (c *FakePolicyV1) Evictions(namespace string) v1.EvictionInterface { + return &FakeEvictions{c, namespace} +} + func (c *FakePolicyV1) PodDisruptionBudgets(namespace string) v1.PodDisruptionBudgetInterface { return &FakePodDisruptionBudgets{c, namespace} } diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/policy_client.go b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/policy_client.go index bb05a686a67..ecd29deb87e 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/policy_client.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/policy/v1/policy_client.go @@ -26,6 +26,7 @@ import ( type PolicyV1Interface interface { RESTClient() rest.Interface + EvictionsGetter PodDisruptionBudgetsGetter } @@ -34,6 +35,10 @@ type PolicyV1Client struct { restClient rest.Interface } +func (c *PolicyV1Client) Evictions(namespace string) EvictionInterface { + return newEvictions(c, namespace) +} + func (c *PolicyV1Client) PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface { return newPodDisruptionBudgets(c, namespace) } diff --git a/staging/src/k8s.io/client-go/listers/policy/v1/eviction.go b/staging/src/k8s.io/client-go/listers/policy/v1/eviction.go new file mode 100644 index 00000000000..dc5ffa0740f --- /dev/null +++ b/staging/src/k8s.io/client-go/listers/policy/v1/eviction.go @@ -0,0 +1,99 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// EvictionLister helps list Evictions. +// All objects returned here must be treated as read-only. +type EvictionLister interface { + // List lists all Evictions in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.Eviction, err error) + // Evictions returns an object that can list and get Evictions. + Evictions(namespace string) EvictionNamespaceLister + EvictionListerExpansion +} + +// evictionLister implements the EvictionLister interface. +type evictionLister struct { + indexer cache.Indexer +} + +// NewEvictionLister returns a new EvictionLister. +func NewEvictionLister(indexer cache.Indexer) EvictionLister { + return &evictionLister{indexer: indexer} +} + +// List lists all Evictions in the indexer. +func (s *evictionLister) List(selector labels.Selector) (ret []*v1.Eviction, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Eviction)) + }) + return ret, err +} + +// Evictions returns an object that can list and get Evictions. +func (s *evictionLister) Evictions(namespace string) EvictionNamespaceLister { + return evictionNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// EvictionNamespaceLister helps list and get Evictions. +// All objects returned here must be treated as read-only. +type EvictionNamespaceLister interface { + // List lists all Evictions in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.Eviction, err error) + // Get retrieves the Eviction from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1.Eviction, error) + EvictionNamespaceListerExpansion +} + +// evictionNamespaceLister implements the EvictionNamespaceLister +// interface. +type evictionNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Evictions in the indexer for a given namespace. +func (s evictionNamespaceLister) List(selector labels.Selector) (ret []*v1.Eviction, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Eviction)) + }) + return ret, err +} + +// Get retrieves the Eviction from the indexer for a given namespace and name. +func (s evictionNamespaceLister) Get(name string) (*v1.Eviction, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("eviction"), name) + } + return obj.(*v1.Eviction), nil +} diff --git a/staging/src/k8s.io/client-go/listers/policy/v1/expansion_generated.go b/staging/src/k8s.io/client-go/listers/policy/v1/expansion_generated.go index c43caf24036..8e2d55a9117 100644 --- a/staging/src/k8s.io/client-go/listers/policy/v1/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/policy/v1/expansion_generated.go @@ -17,3 +17,11 @@ limitations under the License. // Code generated by lister-gen. DO NOT EDIT. package v1 + +// EvictionListerExpansion allows custom methods to be added to +// EvictionLister. +type EvictionListerExpansion interface{} + +// EvictionNamespaceListerExpansion allows custom methods to be added to +// EvictionNamespaceLister. +type EvictionNamespaceListerExpansion interface{} From 33ad842480353f2816873bf728d75333948e4817 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 31 Mar 2021 16:54:55 -0400 Subject: [PATCH 3/6] allow evictions subresource to accept policy/v1 and policy/v1beta1 --- pkg/registry/core/pod/storage/eviction.go | 16 ++- pkg/registry/core/rest/storage_core.go | 2 +- .../pkg/endpoints/handlers/create.go | 2 +- .../apiserver/pkg/endpoints/handlers/rest.go | 21 +++- .../pkg/endpoints/handlers/update.go | 2 +- .../apiserver/pkg/endpoints/installer.go | 3 + .../apiserver/pkg/registry/rest/rest.go | 7 ++ test/e2e/apps/disruption.go | 19 ++- test/e2e/storage/pd.go | 6 +- .../admissionwebhook/admission_test.go | 4 +- test/integration/auth/node_test.go | 10 +- test/integration/evictions/evictions_test.go | 111 ++++++++++++++++-- 12 files changed, 170 insertions(+), 33 deletions(-) diff --git a/pkg/registry/core/pod/storage/eviction.go b/pkg/registry/core/pod/storage/eviction.go index 4e09a899209..ade8ffc3c96 100644 --- a/pkg/registry/core/pod/storage/eviction.go +++ b/pkg/registry/core/pod/storage/eviction.go @@ -23,6 +23,7 @@ import ( "time" policyv1 "k8s.io/api/policy/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -70,10 +71,23 @@ type EvictionREST struct { var _ = rest.NamedCreater(&EvictionREST{}) var _ = rest.GroupVersionKindProvider(&EvictionREST{}) +var _ = rest.GroupVersionAcceptor(&EvictionREST{}) + +var v1Eviction = schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "Eviction"} // GroupVersionKind specifies a particular GroupVersionKind to discovery func (r *EvictionREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { - return schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "Eviction"} + return v1Eviction +} + +// AcceptsGroupVersion indicates both v1 and v1beta1 Eviction objects are acceptable +func (r *EvictionREST) AcceptsGroupVersion(gv schema.GroupVersion) bool { + switch gv { + case policyv1.SchemeGroupVersion, policyv1beta1.SchemeGroupVersion: + return true + default: + return false + } } // New creates a new eviction resource diff --git a/pkg/registry/core/rest/storage_core.go b/pkg/registry/core/rest/storage_core.go index f9323413ea2..42b156b34ea 100644 --- a/pkg/registry/core/rest/storage_core.go +++ b/pkg/registry/core/rest/storage_core.go @@ -313,7 +313,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi if legacyscheme.Scheme.IsVersionRegistered(schema.GroupVersion{Group: "autoscaling", Version: "v1"}) { restStorageMap["replicationControllers/scale"] = controllerStorage.Scale } - if legacyscheme.Scheme.IsVersionRegistered(schema.GroupVersion{Group: "policy", Version: "v1beta1"}) { + if podStorage.Eviction != nil { restStorageMap["pods/eviction"] = podStorage.Eviction } if serviceAccountStorage.Token != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go index 79fc5afabd0..d6f8025e39a 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/create.go @@ -123,7 +123,7 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int scope.err(err, w, req) return } - if gvk.GroupVersion() != gv { + if !scope.AcceptsGroupVersion(gvk.GroupVersion()) { err = errors.NewBadRequest(fmt.Sprintf("the API version in the data (%s) does not match the expected API version (%v)", gvk.GroupVersion().String(), gv.String())) scope.err(err, w, req) return diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go index f618b3867d6..4c2e63e10c0 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go @@ -89,8 +89,14 @@ type RequestScope struct { TableConvertor rest.TableConvertor FieldManager *fieldmanager.FieldManager - Resource schema.GroupVersionResource - Kind schema.GroupVersionKind + Resource schema.GroupVersionResource + Kind schema.GroupVersionKind + + // AcceptsGroupVersionDelegate is an optional delegate that can be queried about whether a given GVK + // can be accepted in create or update requests. If nil, only scope.Kind is accepted. + // Note that this does not enable multi-version support for reads from a single endpoint. + AcceptsGroupVersionDelegate rest.GroupVersionAcceptor + Subresource string MetaGroupVersion schema.GroupVersion @@ -105,6 +111,17 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque responsewriters.ErrorNegotiated(err, scope.Serializer, scope.Kind.GroupVersion(), w, req) } +// AcceptsGroupVersion returns true if the specified GroupVersion is allowed +// in create and update requests. +func (scope *RequestScope) AcceptsGroupVersion(gv schema.GroupVersion) bool { + // If there's a custom acceptor, delegate to it. This is extremely rare. + if scope.AcceptsGroupVersionDelegate != nil { + return scope.AcceptsGroupVersionDelegate.AcceptsGroupVersion(gv) + } + // Fall back to only allowing the singular Kind. This is the typical behavior. + return gv == scope.Kind.GroupVersion() +} + func (scope *RequestScope) AllowsMediaTypeTransform(mimeType, mimeSubType string, gvk *schema.GroupVersionKind) bool { // some handlers like CRDs can't serve all the mime types that PartialObjectMetadata or Table can - if // gvk is nil (no conversion) allow StandardSerializers to further restrict the set of mime types. diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go index b66b57a8b62..ceae03eee39 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/update.go @@ -110,7 +110,7 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa scope.err(err, w, req) return } - if gvk.GroupVersion() != defaultGVK.GroupVersion() { + if !scope.AcceptsGroupVersion(gvk.GroupVersion()) { err = errors.NewBadRequest(fmt.Sprintf("the API version in the data (%s) does not match the expected API version (%s)", gvk.GroupVersion(), defaultGVK.GroupVersion())) scope.err(err, w, req) return diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index 215ecf715ec..caaa4b2e840 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -251,6 +251,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag connecter, isConnecter := storage.(rest.Connecter) storageMeta, isMetadata := storage.(rest.StorageMetadata) storageVersionProvider, isStorageVersionProvider := storage.(rest.StorageVersionProvider) + gvAcceptor, _ := storage.(rest.GroupVersionAcceptor) if !isMetadata { storageMeta = defaultStorageMetadata{} } @@ -587,6 +588,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Subresource: subresource, Kind: fqKindToRegister, + AcceptsGroupVersionDelegate: gvAcceptor, + HubGroupVersion: schema.GroupVersion{Group: fqKindToRegister.Group, Version: runtime.APIVersionInternal}, MetaGroupVersion: metav1.SchemeGroupVersion, diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go index 8dba9b84bf8..a489095d6e0 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -92,6 +92,13 @@ type GroupVersionKindProvider interface { GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind } +// GroupVersionAcceptor is used to determine if a particular GroupVersion is acceptable to send to an endpoint. +// This is used for endpoints which accept multiple versions (which is extremely rare). +// The only known instance is pods/evictions which accepts policy/v1, but also policy/v1beta1 for backwards compatibility. +type GroupVersionAcceptor interface { + AcceptsGroupVersion(gv schema.GroupVersion) bool +} + // Lister is an object that can retrieve resources that match the provided field and label criteria. type Lister interface { // NewList returns an empty object that can be used with the List call. diff --git a/test/e2e/apps/disruption.go b/test/e2e/apps/disruption.go index 4566f77b6c1..9d10a002ad6 100644 --- a/test/e2e/apps/disruption.go +++ b/test/e2e/apps/disruption.go @@ -28,7 +28,6 @@ import ( appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" - policyv1beta1 "k8s.io/api/policy/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -285,7 +284,7 @@ var _ = SIGDescribe("DisruptionController", func() { pod, err := locateRunningPod(cs, ns) framework.ExpectNoError(err) - e := &policyv1beta1.Eviction{ + e := &policyv1.Eviction{ ObjectMeta: metav1.ObjectMeta{ Name: pod.Name, Namespace: ns, @@ -293,7 +292,7 @@ var _ = SIGDescribe("DisruptionController", func() { } if c.shouldDeny { - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) } else { // Only wait for running pods in the "allow" case @@ -304,7 +303,7 @@ var _ = SIGDescribe("DisruptionController", func() { // Since disruptionAllowed starts out false, if an eviction is ever allowed, // that means the controller is working. err = wait.PollImmediate(framework.Poll, timeout, func() (bool, error) { - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) if err != nil { return false, nil } @@ -325,13 +324,13 @@ var _ = SIGDescribe("DisruptionController", func() { pod, err := locateRunningPod(cs, ns) framework.ExpectNoError(err) - e := &policyv1beta1.Eviction{ + e := &policyv1.Eviction{ ObjectMeta: metav1.ObjectMeta{ Name: pod.Name, Namespace: ns, }, } - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) ginkgo.By("Updating the pdb to allow a pod to be evicted") @@ -344,7 +343,7 @@ var _ = SIGDescribe("DisruptionController", func() { ginkgo.By("Trying to evict the same pod we tried earlier which should now be evictable") waitForPodsOrDie(cs, ns, 3) waitForPdbToObserveHealthyPods(cs, ns, 3) - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) framework.ExpectNoError(err) // the eviction is now allowed ginkgo.By("Patching the pdb to disallow a pod to be evicted") @@ -362,13 +361,13 @@ var _ = SIGDescribe("DisruptionController", func() { waitForPodsOrDie(cs, ns, 3) pod, err = locateRunningPod(cs, ns) // locate a new running pod framework.ExpectNoError(err) - e = &policyv1beta1.Eviction{ + e = &policyv1.Eviction{ ObjectMeta: metav1.ObjectMeta{ Name: pod.Name, Namespace: ns, }, } - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) ginkgo.By("Deleting the pdb to allow a pod to be evicted") @@ -376,7 +375,7 @@ var _ = SIGDescribe("DisruptionController", func() { ginkgo.By("Trying to evict the same pod we tried earlier which should now be evictable") waitForPodsOrDie(cs, ns, 3) - err = cs.CoreV1().Pods(ns).Evict(context.TODO(), e) + err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) framework.ExpectNoError(err) // the eviction is now allowed }) diff --git a/test/e2e/storage/pd.go b/test/e2e/storage/pd.go index b3dc2ffd015..da8c00c6574 100644 --- a/test/e2e/storage/pd.go +++ b/test/e2e/storage/pd.go @@ -30,7 +30,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/onsi/ginkgo" v1 "k8s.io/api/core/v1" - policyv1beta1 "k8s.io/api/policy/v1beta1" + policyv1 "k8s.io/api/policy/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -423,7 +423,7 @@ var _ = utils.SIGDescribe("Pod Disks", func() { framework.ExpectNoError(podClient.Delete(context.TODO(), host0Pod.Name, *metav1.NewDeleteOptions(0)), "Unable to delete host0Pod") } else if disruptOp == evictPod { - evictTarget := &policyv1beta1.Eviction{ + evictTarget := &policyv1.Eviction{ ObjectMeta: metav1.ObjectMeta{ Name: host0Pod.Name, Namespace: ns, @@ -431,7 +431,7 @@ var _ = utils.SIGDescribe("Pod Disks", func() { } ginkgo.By("evicting host0Pod") err = wait.PollImmediate(framework.Poll, podEvictTimeout, func() (bool, error) { - if err := cs.CoreV1().Pods(ns).Evict(context.TODO(), evictTarget); err != nil { + if err := cs.CoreV1().Pods(ns).EvictV1(context.TODO(), evictTarget); err != nil { framework.Logf("Failed to evict host0Pod, ignoring error: %v", err) return false, nil } diff --git a/test/integration/apiserver/admissionwebhook/admission_test.go b/test/integration/apiserver/admissionwebhook/admission_test.go index d88d6fa08b6..08b87f93b5c 100644 --- a/test/integration/apiserver/admissionwebhook/admission_test.go +++ b/test/integration/apiserver/admissionwebhook/admission_test.go @@ -42,7 +42,7 @@ import ( corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" - policyv1beta1 "k8s.io/api/policy/v1beta1" + policyv1 "k8s.io/api/policy/v1" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -1128,7 +1128,7 @@ func testPodBindingEviction(c *testContext) { }).Do(context.TODO()).Error() case gvr("", "v1", "pods/eviction"): - err = c.clientset.CoreV1().RESTClient().Post().Namespace(pod.GetNamespace()).Resource("pods").Name(pod.GetName()).SubResource("eviction").Body(&policyv1beta1.Eviction{ + err = c.clientset.CoreV1().RESTClient().Post().Namespace(pod.GetNamespace()).Resource("pods").Name(pod.GetName()).SubResource("eviction").Body(&policyv1.Eviction{ ObjectMeta: metav1.ObjectMeta{Name: pod.GetName()}, DeleteOptions: &forceDelete, }).Do(context.TODO()).Error() diff --git a/test/integration/auth/node_test.go b/test/integration/auth/node_test.go index 86a2354d7d8..2f32df52bbd 100644 --- a/test/integration/auth/node_test.go +++ b/test/integration/auth/node_test.go @@ -26,7 +26,7 @@ import ( coordination "k8s.io/api/coordination/v1" corev1 "k8s.io/api/core/v1" - policy "k8s.io/api/policy/v1beta1" + policy "k8s.io/api/policy/v1" storagev1 "k8s.io/api/storage/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -305,9 +305,9 @@ func TestNodeAuthorizer(t *testing.T) { createNode2NormalPodEviction := func(client clientset.Interface) func() error { return func() error { zero := int64(0) - return client.PolicyV1beta1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ + return client.PolicyV1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ TypeMeta: metav1.TypeMeta{ - APIVersion: "policy/v1beta1", + APIVersion: "policy/v1", Kind: "Eviction", }, ObjectMeta: metav1.ObjectMeta{ @@ -321,9 +321,9 @@ func TestNodeAuthorizer(t *testing.T) { createNode2MirrorPodEviction := func(client clientset.Interface) func() error { return func() error { zero := int64(0) - return client.PolicyV1beta1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ + return client.PolicyV1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ TypeMeta: metav1.TypeMeta{ - APIVersion: "policy/v1beta1", + APIVersion: "policy/v1", Kind: "Eviction", }, ObjectMeta: metav1.ObjectMeta{ diff --git a/test/integration/evictions/evictions_test.go b/test/integration/evictions/evictions_test.go index 1c592c09dfe..2c2d4144808 100644 --- a/test/integration/evictions/evictions_test.go +++ b/test/integration/evictions/evictions_test.go @@ -18,9 +18,11 @@ package evictions import ( "context" + "encoding/json" "fmt" "net/http/httptest" "reflect" + "strings" "sync" "sync/atomic" "testing" @@ -31,6 +33,10 @@ import ( policyv1beta1 "k8s.io/api/policy/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" @@ -110,10 +116,10 @@ func TestConcurrentEvictionRequests(t *testing.T) { go func(id int, errCh chan error) { defer wg.Done() podName := fmt.Sprintf(podNameFormat, id) - eviction := newV1beta1Eviction(ns.Name, podName, deleteOption) + eviction := newV1Eviction(ns.Name, podName, deleteOption) err := wait.PollImmediate(5*time.Second, 60*time.Second, func() (bool, error) { - e := clientSet.PolicyV1beta1().Evictions(ns.Name).Evict(context.TODO(), eviction) + e := clientSet.PolicyV1().Evictions(ns.Name).Evict(context.TODO(), eviction) switch { case apierrors.IsTooManyRequests(e): return false, nil @@ -219,9 +225,9 @@ func TestTerminalPodEviction(t *testing.T) { t.Fatalf("Error while listing pod disruption budget") } oldPdb := pdbList.Items[0] - eviction := newV1beta1Eviction(ns.Name, pod.Name, deleteOption) + eviction := newV1Eviction(ns.Name, pod.Name, deleteOption) err = wait.PollImmediate(5*time.Second, 60*time.Second, func() (bool, error) { - e := clientSet.PolicyV1beta1().Evictions(ns.Name).Evict(context.TODO(), eviction) + e := clientSet.PolicyV1().Evictions(ns.Name).Evict(context.TODO(), eviction) switch { case apierrors.IsTooManyRequests(e): return false, nil @@ -251,6 +257,97 @@ func TestTerminalPodEviction(t *testing.T) { } } +// TestEvictionVersions ensures the eviction endpoint accepts and returns the correct API versions +func TestEvictionVersions(t *testing.T) { + s, closeFn, rm, informers, clientSet := rmSetup(t) + defer closeFn() + + stopCh := make(chan struct{}) + informers.Start(stopCh) + go rm.Run(stopCh) + defer close(stopCh) + + config := restclient.Config{Host: s.URL} + + ns := "default" + subresource := "eviction" + pod := newPod("test") + if _, err := clientSet.CoreV1().Pods(ns).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil { + t.Errorf("Failed to create pod: %v", err) + } + + dynamicClient, err := dynamic.NewForConfig(&config) + if err != nil { + t.Fatalf("Failed to create clientset: %v", err) + } + + podClient := dynamicClient.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}).Namespace(ns) + + // get should not be supported + if _, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{}, subresource); !apierrors.IsMethodNotSupported(err) { + t.Fatalf("expected MethodNotSupported for GET, got %v", err) + } + + // patch should not be supported + for _, patchType := range []types.PatchType{types.JSONPatchType, types.MergePatchType, types.StrategicMergePatchType, types.ApplyPatchType} { + if _, err := podClient.Patch(context.TODO(), pod.Name, patchType, []byte{}, metav1.PatchOptions{}, subresource); !apierrors.IsMethodNotSupported(err) { + t.Fatalf("expected MethodNotSupported for GET, got %v", err) + } + } + + allowedEvictions := []runtime.Object{ + // v1beta1, no apiVersion/kind + &policyv1beta1.Eviction{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{Name: pod.Name}, + DeleteOptions: &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, + }, + // v1beta1, apiVersion/kind + &policyv1beta1.Eviction{ + TypeMeta: metav1.TypeMeta{APIVersion: "policy/v1beta1", Kind: "Eviction"}, + ObjectMeta: metav1.ObjectMeta{Name: pod.Name}, + DeleteOptions: &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, + }, + // v1, no apiVersion/kind + &policyv1.Eviction{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{Name: pod.Name}, + DeleteOptions: &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, + }, + // v1, apiVersion/kind + &policyv1.Eviction{ + TypeMeta: metav1.TypeMeta{APIVersion: "policy/v1", Kind: "Eviction"}, + ObjectMeta: metav1.ObjectMeta{Name: pod.Name}, + DeleteOptions: &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, + }, + } + v1Status := schema.GroupVersionKind{Version: "v1", Kind: "Status"} + for _, allowedEviction := range allowedEvictions { + data, _ := json.Marshal(allowedEviction) + u := &unstructured.Unstructured{} + json.Unmarshal(data, u) + result, err := podClient.Create(context.TODO(), u, metav1.CreateOptions{}, subresource) + if err != nil { + t.Fatalf("error posting %s: %v", string(data), err) + } + if result.GroupVersionKind() != v1Status { + t.Fatalf("expected v1 Status, got %#v", result) + } + } + + // create unknown eviction version with apiVersion/kind should fail + u := &unstructured.Unstructured{Object: map[string]interface{}{ + "metadata": map[string]interface{}{"name": pod.Name}, + "apiVersion": "policy/v2", + "kind": "Eviction", + }} + if _, err := podClient.Create(context.TODO(), u, metav1.CreateOptions{}, subresource); err == nil { + t.Fatal("expected error posting unknown Eviction version, got none") + } else if !strings.Contains(err.Error(), "policy/v2") { + t.Fatalf("expected error about policy/v2, got %#v", err) + } +} + func newPod(podName string) *v1.Pod { return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -309,10 +406,10 @@ func newPDB() *policyv1.PodDisruptionBudget { } } -func newV1beta1Eviction(ns, evictionName string, deleteOption metav1.DeleteOptions) *policyv1beta1.Eviction { - return &policyv1beta1.Eviction{ +func newV1Eviction(ns, evictionName string, deleteOption metav1.DeleteOptions) *policyv1.Eviction { + return &policyv1.Eviction{ TypeMeta: metav1.TypeMeta{ - APIVersion: "Policy/v1beta1", + APIVersion: "policy/v1", Kind: "Eviction", }, ObjectMeta: metav1.ObjectMeta{ From f07fc213b07568442b22757b2220b80a5041cced Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 1 Apr 2021 22:50:59 -0400 Subject: [PATCH 4/6] kubectl: send policy/v1 evictions to servers that support it --- .../kubectl/pkg/cmd/drain/drain_test.go | 11 +-- .../k8s.io/kubectl/pkg/cmd/testing/fake.go | 1 + staging/src/k8s.io/kubectl/pkg/drain/drain.go | 80 +++++++++---------- .../k8s.io/kubectl/pkg/drain/drain_test.go | 66 ++++++++++----- 4 files changed, 90 insertions(+), 68 deletions(-) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain_test.go b/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain_test.go index 34568342b7b..eacef7fd300 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain_test.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain_test.go @@ -34,7 +34,6 @@ import ( appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" - policyv1beta1 "k8s.io/api/policy/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -767,7 +766,7 @@ func TestDrain(t *testing.T) { { Name: "policy", PreferredVersion: metav1.GroupVersionForDiscovery{ - GroupVersion: "policy/v1beta1", + GroupVersion: "policy/v1", }, }, }, @@ -780,8 +779,10 @@ func TestDrain(t *testing.T) { if testEviction { resourceList.APIResources = []metav1.APIResource{ { - Name: drain.EvictionSubresource, - Kind: drain.EvictionKind, + Name: drain.EvictionSubresource, + Kind: drain.EvictionKind, + Group: "policy", + Version: "v1", }, } } @@ -849,7 +850,7 @@ func TestDrain(t *testing.T) { if test.failUponEvictionOrDeletion { return nil, errors.New("request failed") } - return &http.Response{StatusCode: http.StatusCreated, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &policyv1beta1.Eviction{})}, nil + return &http.Response{StatusCode: http.StatusCreated, Header: cmdtesting.DefaultHeader(), Body: cmdtesting.ObjBody(codec, &metav1.Status{})}, nil default: t.Fatalf("%s: unexpected request: %v %#v\n%#v", test.description, req.Method, req.URL, req) return nil, nil diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go b/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go index db0ac18bd4f..0fc3c86f3d2 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go @@ -565,6 +565,7 @@ func (f *TestFactory) KubernetesClientSet() (*kubernetes.Clientset, error) { clientset.AppsV1beta2().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client clientset.AppsV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client clientset.PolicyV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client + clientset.PolicyV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client clientset.DiscoveryClient.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client return clientset, nil diff --git a/staging/src/k8s.io/kubectl/pkg/drain/drain.go b/staging/src/k8s.io/kubectl/pkg/drain/drain.go index 26585814750..84b9eb2b73f 100644 --- a/staging/src/k8s.io/kubectl/pkg/drain/drain.go +++ b/staging/src/k8s.io/kubectl/pkg/drain/drain.go @@ -24,12 +24,14 @@ import ( "time" corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/resource" @@ -103,35 +105,21 @@ type waitForDeleteParams struct { // CheckEvictionSupport uses Discovery API to find out if the server support // eviction subresource If support, it will return its groupVersion; Otherwise, -// it will return an empty string -func CheckEvictionSupport(clientset kubernetes.Interface) (string, error) { +// it will return an empty GroupVersion +func CheckEvictionSupport(clientset kubernetes.Interface) (schema.GroupVersion, error) { discoveryClient := clientset.Discovery() - groupList, err := discoveryClient.ServerGroups() - if err != nil { - return "", err - } - foundPolicyGroup := false - var policyGroupVersion string - for _, group := range groupList.Groups { - if group.Name == "policy" { - foundPolicyGroup = true - policyGroupVersion = group.PreferredVersion.GroupVersion - break - } - } - if !foundPolicyGroup { - return "", nil - } + + // version info available in subresources since v1.8.0 in https://github.com/kubernetes/kubernetes/pull/49971 resourceList, err := discoveryClient.ServerResourcesForGroupVersion("v1") if err != nil { - return "", err + return schema.GroupVersion{}, err } for _, resource := range resourceList.APIResources { - if resource.Name == EvictionSubresource && resource.Kind == EvictionKind { - return policyGroupVersion, nil + if resource.Name == EvictionSubresource && resource.Kind == EvictionKind && len(resource.Group) > 0 && len(resource.Version) > 0 { + return schema.GroupVersion{Group: resource.Group, Version: resource.Version}, nil } } - return "", nil + return schema.GroupVersion{}, nil } func (d *Helper) makeDeleteOptions() metav1.DeleteOptions { @@ -157,7 +145,7 @@ func (d *Helper) DeletePod(pod corev1.Pod) error { } // EvictPod will evict the give pod, or return an error if it couldn't -func (d *Helper) EvictPod(pod corev1.Pod, policyGroupVersion string) error { +func (d *Helper) EvictPod(pod corev1.Pod, evictionGroupVersion schema.GroupVersion) error { if d.DryRunStrategy == cmdutil.DryRunServer { if err := d.DryRunVerifier.HasSupport(pod.GroupVersionKind()); err != nil { return err @@ -165,20 +153,30 @@ func (d *Helper) EvictPod(pod corev1.Pod, policyGroupVersion string) error { } delOpts := d.makeDeleteOptions() - eviction := &policyv1beta1.Eviction{ - TypeMeta: metav1.TypeMeta{ - APIVersion: policyGroupVersion, - Kind: EvictionKind, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: pod.Name, - Namespace: pod.Namespace, - }, - DeleteOptions: &delOpts, - } - // Remember to change change the URL manipulation func when Eviction's version change - return d.Client.PolicyV1beta1().Evictions(eviction.Namespace).Evict(d.getContext(), eviction) + switch evictionGroupVersion { + case policyv1.SchemeGroupVersion: + // send policy/v1 if the server supports it + eviction := &policyv1.Eviction{ + ObjectMeta: metav1.ObjectMeta{ + Name: pod.Name, + Namespace: pod.Namespace, + }, + DeleteOptions: &delOpts, + } + return d.Client.PolicyV1().Evictions(eviction.Namespace).Evict(context.TODO(), eviction) + + default: + // otherwise, fall back to policy/v1beta1, supported by all servers that support the eviction subresource + eviction := &policyv1beta1.Eviction{ + ObjectMeta: metav1.ObjectMeta{ + Name: pod.Name, + Namespace: pod.Namespace, + }, + DeleteOptions: &delOpts, + } + return d.Client.PolicyV1beta1().Evictions(eviction.Namespace).Evict(context.TODO(), eviction) + } } // GetPodsForDeletion receives resource info for a node, and returns those pods as PodDeleteList, @@ -259,20 +257,20 @@ func (d *Helper) DeleteOrEvictPods(pods []corev1.Pod) error { } if !d.DisableEviction { - policyGroupVersion, err := CheckEvictionSupport(d.Client) + evictionGroupVersion, err := CheckEvictionSupport(d.Client) if err != nil { return err } - if len(policyGroupVersion) > 0 { - return d.evictPods(pods, policyGroupVersion, getPodFn) + if !evictionGroupVersion.Empty() { + return d.evictPods(pods, evictionGroupVersion, getPodFn) } } return d.deletePods(pods, getPodFn) } -func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodFn func(namespace, name string) (*corev1.Pod, error)) error { +func (d *Helper) evictPods(pods []corev1.Pod, evictionGroupVersion schema.GroupVersion, getPodFn func(namespace, name string) (*corev1.Pod, error)) error { returnCh := make(chan error, 1) // 0 timeout means infinite, we use MaxInt64 to represent it. var globalTimeout time.Duration @@ -313,7 +311,7 @@ func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodF refreshPod = false } - err := d.EvictPod(activePod, policyGroupVersion) + err := d.EvictPod(activePod, evictionGroupVersion) if err == nil { break } else if apierrors.IsNotFound(err) { diff --git a/staging/src/k8s.io/kubectl/pkg/drain/drain_test.go b/staging/src/k8s.io/kubectl/pkg/drain/drain_test.go index dc95e08124f..78efab1fdc9 100644 --- a/staging/src/k8s.io/kubectl/pkg/drain/drain_test.go +++ b/staging/src/k8s.io/kubectl/pkg/drain/drain_test.go @@ -29,6 +29,7 @@ import ( "time" corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -214,13 +215,20 @@ func createPods(ifCreateNewPods bool) (map[string]corev1.Pod, []corev1.Pod) { return podMap, podSlice } +func addCoreNonEvictionSupport(t *testing.T, k *fake.Clientset) { + coreResources := &metav1.APIResourceList{ + GroupVersion: "v1", + } + k.Resources = append(k.Resources, coreResources) +} + // addEvictionSupport implements simple fake eviction support on the fake.Clientset -func addEvictionSupport(t *testing.T, k *fake.Clientset) { +func addEvictionSupport(t *testing.T, k *fake.Clientset, version string) { podsEviction := metav1.APIResource{ Name: "pods/eviction", Kind: "Eviction", - Group: "", - Version: "v1", + Group: "policy", + Version: version, } coreResources := &metav1.APIResourceList{ GroupVersion: "v1", @@ -238,13 +246,26 @@ func addEvictionSupport(t *testing.T, k *fake.Clientset) { return false, nil, nil } - eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction) + namespace := "" + name := "" + switch version { + case "v1": + eviction := *action.(ktest.CreateAction).GetObject().(*policyv1.Eviction) + namespace = eviction.Namespace + name = eviction.Name + case "v1beta1": + eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction) + namespace = eviction.Namespace + name = eviction.Name + default: + t.Errorf("unknown version %s", version) + } // Avoid the lock go func() { - err := k.CoreV1().Pods(eviction.Namespace).Delete(context.TODO(), eviction.Name, metav1.DeleteOptions{}) + err := k.CoreV1().Pods(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) if err != nil { // Errorf because we can't call Fatalf from another goroutine - t.Errorf("failed to delete pod: %s/%s", eviction.Namespace, eviction.Name) + t.Errorf("failed to delete pod: %s/%s", namespace, name) } }() @@ -253,22 +274,23 @@ func addEvictionSupport(t *testing.T, k *fake.Clientset) { } func TestCheckEvictionSupport(t *testing.T) { - for _, evictionSupported := range []bool{true, false} { - evictionSupported := evictionSupported - t.Run(fmt.Sprintf("evictionSupported=%v", evictionSupported), + for _, evictionVersion := range []string{"", "v1", "v1beta1"} { + t.Run(fmt.Sprintf("evictionVersion=%v", evictionVersion), func(t *testing.T) { k := fake.NewSimpleClientset() - if evictionSupported { - addEvictionSupport(t, k) + if len(evictionVersion) > 0 { + addEvictionSupport(t, k, evictionVersion) + } else { + addCoreNonEvictionSupport(t, k) } apiGroup, err := CheckEvictionSupport(k) if err != nil { t.Fatalf("unexpected error: %v", err) } - expectedAPIGroup := "" - if evictionSupported { - expectedAPIGroup = "policy/v1" + expectedAPIGroup := schema.GroupVersion{} + if len(evictionVersion) > 0 { + expectedAPIGroup = schema.GroupVersion{Group: "policy", Version: evictionVersion} } if apiGroup != expectedAPIGroup { t.Fatalf("expected apigroup %q, actual=%q", expectedAPIGroup, apiGroup) @@ -312,7 +334,7 @@ func TestDeleteOrEvict(t *testing.T) { } // Create 4 pods, and try to remove the first 2 - var expectedEvictions []policyv1beta1.Eviction + var expectedEvictions []policyv1.Eviction var create []runtime.Object deletePods := []corev1.Pod{} for i := 1; i <= 4; i++ { @@ -325,9 +347,7 @@ func TestDeleteOrEvict(t *testing.T) { deletePods = append(deletePods, *pod) if tc.evictionSupported && !tc.disableEviction { - eviction := policyv1beta1.Eviction{} - eviction.Kind = "Eviction" - eviction.APIVersion = "policy/v1" + eviction := policyv1.Eviction{} eviction.Namespace = pod.Namespace eviction.Name = pod.Name @@ -344,7 +364,9 @@ func TestDeleteOrEvict(t *testing.T) { // Build the fake client k := fake.NewSimpleClientset(create...) if tc.evictionSupported { - addEvictionSupport(t, k) + addEvictionSupport(t, k, "v1") + } else { + addCoreNonEvictionSupport(t, k) } h.Client = k h.DisableEviction = tc.disableEviction @@ -372,19 +394,19 @@ func TestDeleteOrEvict(t *testing.T) { } // Test that pods were evicted as expected - var actualEvictions []policyv1beta1.Eviction + var actualEvictions []policyv1.Eviction for _, action := range k.Actions() { if action.GetVerb() != "create" || action.GetResource().Resource != "pods" || action.GetSubresource() != "eviction" { continue } - eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction) + eviction := *action.(ktest.CreateAction).GetObject().(*policyv1.Eviction) actualEvictions = append(actualEvictions, eviction) } sort.Slice(actualEvictions, func(i, j int) bool { return actualEvictions[i].Name < actualEvictions[j].Name }) if !reflect.DeepEqual(actualEvictions, expectedEvictions) { - t.Errorf("%s: unexpected evictions; actual %v; expected %v", tc.description, actualEvictions, expectedEvictions) + t.Errorf("%s: unexpected evictions; actual\n\t%v\nexpected\n\t%v", tc.description, actualEvictions, expectedEvictions) } }) } From 10b07085f8cc5a5a6dd6d6e6a48324b89fcf8770 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Wed, 14 Apr 2021 09:12:21 -0400 Subject: [PATCH 5/6] Define constant for eviction failure cause --- pkg/registry/core/pod/storage/eviction.go | 4 ++-- staging/src/k8s.io/api/policy/v1/types.go | 3 +++ test/e2e/apps/disruption.go | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/registry/core/pod/storage/eviction.go b/pkg/registry/core/pod/storage/eviction.go index ade8ffc3c96..d1ed12fb59b 100644 --- a/pkg/registry/core/pod/storage/eviction.go +++ b/pkg/registry/core/pod/storage/eviction.go @@ -323,7 +323,7 @@ func createTooManyRequestsError(name string) error { // even without that, we can give a suggestion (even if small) that // prevents well-behaved clients from hammering us. err := errors.NewTooManyRequests("Cannot evict pod as it would violate the pod's disruption budget.", 10) - err.ErrStatus.Details.Causes = append(err.ErrStatus.Details.Causes, metav1.StatusCause{Type: "DisruptionBudget", Message: fmt.Sprintf("The disruption budget %s is still being processed by the server.", name)}) + err.ErrStatus.Details.Causes = append(err.ErrStatus.Details.Causes, metav1.StatusCause{Type: policyv1.DisruptionBudgetCause, Message: fmt.Sprintf("The disruption budget %s is still being processed by the server.", name)}) return err } @@ -341,7 +341,7 @@ func (r *EvictionREST) checkAndDecrement(namespace string, podName string, pdb p } if pdb.Status.DisruptionsAllowed == 0 { err := errors.NewTooManyRequests("Cannot evict pod as it would violate the pod's disruption budget.", 0) - err.ErrStatus.Details.Causes = append(err.ErrStatus.Details.Causes, metav1.StatusCause{Type: "DisruptionBudget", Message: fmt.Sprintf("The disruption budget %s needs %d healthy pods and has %d currently", pdb.Name, pdb.Status.DesiredHealthy, pdb.Status.CurrentHealthy)}) + err.ErrStatus.Details.Causes = append(err.ErrStatus.Details.Causes, metav1.StatusCause{Type: policyv1.DisruptionBudgetCause, Message: fmt.Sprintf("The disruption budget %s needs %d healthy pods and has %d currently", pdb.Name, pdb.Status.DesiredHealthy, pdb.Status.CurrentHealthy)}) return err } diff --git a/staging/src/k8s.io/api/policy/v1/types.go b/staging/src/k8s.io/api/policy/v1/types.go index f621e784f76..4a03696f000 100644 --- a/staging/src/k8s.io/api/policy/v1/types.go +++ b/staging/src/k8s.io/api/policy/v1/types.go @@ -21,6 +21,9 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) +// DisruptionBudgetCause is the status cause returned for eviction failures caused by PodDisruptionBudget violations. +const DisruptionBudgetCause metav1.CauseType = "DisruptionBudget" + // PodDisruptionBudgetSpec is a description of a PodDisruptionBudget. type PodDisruptionBudgetSpec struct { // An eviction is allowed if at least "minAvailable" pods selected by diff --git a/test/e2e/apps/disruption.go b/test/e2e/apps/disruption.go index 9d10a002ad6..5b91d29d6c0 100644 --- a/test/e2e/apps/disruption.go +++ b/test/e2e/apps/disruption.go @@ -23,7 +23,6 @@ import ( jsonpatch "github.com/evanphx/json-patch" "github.com/onsi/ginkgo" - "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" @@ -293,7 +292,8 @@ var _ = SIGDescribe("DisruptionController", func() { if c.shouldDeny { err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) - gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) + framework.ExpectError(err, "pod eviction should fail") + framework.ExpectEqual(apierrors.HasStatusCause(err, policyv1.DisruptionBudgetCause), true, "pod eviction should fail with DisruptionBudget cause") } else { // Only wait for running pods in the "allow" case // because one of shouldDeny cases relies on the @@ -331,7 +331,8 @@ var _ = SIGDescribe("DisruptionController", func() { }, } err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) - gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) + framework.ExpectError(err, "pod eviction should fail") + framework.ExpectEqual(apierrors.HasStatusCause(err, policyv1.DisruptionBudgetCause), true, "pod eviction should fail with DisruptionBudget cause") ginkgo.By("Updating the pdb to allow a pod to be evicted") updatePDBOrDie(cs, ns, defaultName, func(pdb *policyv1.PodDisruptionBudget) *policyv1.PodDisruptionBudget { @@ -368,7 +369,8 @@ var _ = SIGDescribe("DisruptionController", func() { }, } err = cs.CoreV1().Pods(ns).EvictV1(context.TODO(), e) - gomega.Expect(err).Should(gomega.MatchError("Cannot evict pod as it would violate the pod's disruption budget.")) + framework.ExpectError(err, "pod eviction should fail") + framework.ExpectEqual(apierrors.HasStatusCause(err, policyv1.DisruptionBudgetCause), true, "pod eviction should fail with DisruptionBudget cause") ginkgo.By("Deleting the pdb to allow a pod to be evicted") deletePDBOrDie(cs, ns, defaultName) From a07d4460bf587d5771fa2df29ff5a628aec8769c Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 1 Apr 2021 23:18:45 -0400 Subject: [PATCH 6/6] Promote e2e eviction test to conformance --- test/conformance/testdata/conformance.yaml | 8 ++++++++ test/e2e/apps/disruption.go | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/test/conformance/testdata/conformance.yaml b/test/conformance/testdata/conformance.yaml index aec70459a03..e840ff9ac8d 100755 --- a/test/conformance/testdata/conformance.yaml +++ b/test/conformance/testdata/conformance.yaml @@ -704,6 +704,14 @@ description: PodDisruptionBudget API must support list and deletecollection operations. release: v1.21 file: test/e2e/apps/disruption.go +- testname: 'PodDisruptionBudget: block an eviction until the PDB is updated to allow + it' + codename: '[sig-apps] DisruptionController should block an eviction until the PDB + is updated to allow it [Conformance]' + description: Eviction API must block an eviction until the PDB is updated to allow + it + release: v1.22 + file: test/e2e/apps/disruption.go - testname: 'PodDisruptionBudget: create, update, patch, and delete object' codename: '[sig-apps] DisruptionController should create a PodDisruptionBudget [Conformance]' description: PodDisruptionBudget API must support create, update, patch, and delete diff --git a/test/e2e/apps/disruption.go b/test/e2e/apps/disruption.go index 5b91d29d6c0..46ce07e5d46 100644 --- a/test/e2e/apps/disruption.go +++ b/test/e2e/apps/disruption.go @@ -314,7 +314,12 @@ var _ = SIGDescribe("DisruptionController", func() { }) } - ginkgo.It("should block an eviction until the PDB is updated to allow it", func() { + /* + Release : v1.22 + Testname: PodDisruptionBudget: block an eviction until the PDB is updated to allow it + Description: Eviction API must block an eviction until the PDB is updated to allow it + */ + framework.ConformanceIt("should block an eviction until the PDB is updated to allow it", func() { ginkgo.By("Creating a pdb that targets all three pods in a test replica set") createPDBMinAvailableOrDie(cs, ns, defaultName, intstr.FromInt(3), defaultLabels) createReplicaSetOrDie(cs, ns, 3, false)