Merge pull request #99290 from mortent/PromotePDBsToGA

Promote PodDisruptionBudget to policy/v1
This commit is contained in:
Kubernetes Prow Robot 2021-03-09 11:05:05 -08:00 committed by GitHub
commit 046ad61479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 6397 additions and 245 deletions

File diff suppressed because it is too large Load Diff

View File

@ -262,6 +262,7 @@ var apiVersionPriorities = map[schema.GroupVersion]priority{
{Group: "networking.k8s.io", Version: "v1"}: {group: 17200, version: 15},
{Group: "networking.k8s.io", Version: "v1beta1"}: {group: 17200, version: 9},
{Group: "extensions", Version: "v1beta1"}: {group: 17150, version: 1}, // prioritize below networking.k8s.io, which contains the GA version of Ingress, the only resource remaining in extensions/v1beta1
{Group: "policy", Version: "v1"}: {group: 17100, version: 15},
{Group: "policy", Version: "v1beta1"}: {group: 17100, version: 9},
{Group: "rbac.authorization.k8s.io", Version: "v1"}: {group: 17000, version: 15},
{Group: "rbac.authorization.k8s.io", Version: "v1beta1"}: {group: 17000, version: 12},

View File

@ -25,7 +25,6 @@ import (
"k8s.io/klog/v2"
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/scale"
@ -34,16 +33,6 @@ import (
)
func startDisruptionController(ctx ControllerContext) (http.Handler, bool, error) {
var group = "policy"
var version = "v1beta1"
var resource = "poddisruptionbudgets"
if !ctx.AvailableResources[schema.GroupVersionResource{Group: group, Version: version, Resource: resource}] {
klog.Infof(
"Refusing to start disruption because resource %q in group %q is not available.",
resource, group+"/"+version)
return nil, false, nil
}
if !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.PodDisruptionBudget) {
klog.Infof("Refusing to start disruption because the PodDisruptionBudget feature is disabled")
return nil, false, nil
@ -59,7 +48,7 @@ func startDisruptionController(ctx ControllerContext) (http.Handler, bool, error
go disruption.NewDisruptionController(
ctx.InformerFactory.Core().V1().Pods(),
ctx.InformerFactory.Policy().V1beta1().PodDisruptionBudgets(),
ctx.InformerFactory.Policy().V1().PodDisruptionBudgets(),
ctx.InformerFactory.Core().V1().ReplicationControllers(),
ctx.InformerFactory.Apps().V1().ReplicaSets(),
ctx.InformerFactory.Apps().V1().Deployments(),

View File

@ -28,6 +28,7 @@
"k8s.io/api/node/v1alpha1": "nodev1alpha1",
"k8s.io/api/node/v1beta1": "nodev1beta1",
"k8s.io/api/node/v1": "nodev1",
"k8s.io/api/policy/v1": "policyv1",
"k8s.io/api/policy/v1beta1": "policyv1beta1",
"k8s.io/api/rbac/v1": "rbacv1",
"k8s.io/api/rbac/v1alpha1": "rbacv1alpha1",

View File

@ -95,6 +95,7 @@ networking.k8s.io/v1beta1 \
node.k8s.io/v1 \
node.k8s.io/v1alpha1 \
node.k8s.io/v1beta1 \
policy/v1 \
policy/v1beta1 \
rbac.authorization.k8s.io/v1 \
rbac.authorization.k8s.io/v1beta1 \

51
pkg/apis/policy/helper.go Normal file
View File

@ -0,0 +1,51 @@
/*
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 policy
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
PDBV1beta1Label = "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match"
)
var (
NonV1beta1MatchAllSelector = &metav1.LabelSelector{}
NonV1beta1MatchNoneSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{Key: PDBV1beta1Label, Operator: metav1.LabelSelectorOpExists}},
}
V1beta1MatchNoneSelector = &metav1.LabelSelector{}
V1beta1MatchAllSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{Key: PDBV1beta1Label, Operator: metav1.LabelSelectorOpDoesNotExist}},
}
)
func StripPDBV1beta1Label(selector *metav1.LabelSelector) {
if selector == nil {
return
}
trimmedMatchExpressions := selector.MatchExpressions[:0]
for _, exp := range selector.MatchExpressions {
if exp.Key != PDBV1beta1Label {
trimmedMatchExpressions = append(trimmedMatchExpressions, exp)
}
}
selector.MatchExpressions = trimmedMatchExpressions
}

View File

@ -23,6 +23,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/apis/policy/v1"
"k8s.io/kubernetes/pkg/apis/policy/v1beta1"
)
@ -34,5 +35,7 @@ func init() {
func Install(scheme *runtime.Scheme) {
utilruntime.Must(policy.AddToScheme(scheme))
utilruntime.Must(v1beta1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1beta1.SchemeGroupVersion))
utilruntime.Must(v1.AddToScheme(scheme))
// TODO (mortent): priority should change after 1.21. See https://github.com/kubernetes/kubernetes/pull/95718#discussion_r520969477
utilruntime.Must(scheme.SetVersionPriority(v1beta1.SchemeGroupVersion, v1.SchemeGroupVersion))
}

View File

@ -0,0 +1,42 @@
/*
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 (
"k8s.io/api/policy/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/kubernetes/pkg/apis/policy"
)
func Convert_v1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *v1.PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error {
if err := autoConvert_v1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in, out, s); err != nil {
return err
}
switch {
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.NonV1beta1MatchNoneSelector):
// no-op, preserve
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.NonV1beta1MatchAllSelector):
// no-op, preserve
default:
// otherwise, make sure the label intended to be used in a match-all or match-none selector
// never gets combined with user-specified fields
policy.StripPDBV1beta1Label(out.Spec.Selector)
}
return nil
}

View File

@ -0,0 +1,127 @@
/*
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 (
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/apis/policy"
)
func TestConversion(t *testing.T) {
testcases := []struct {
Name string
In runtime.Object
Out runtime.Object
ExpectOut runtime.Object
ExpectErr string
}{
{
Name: "v1 to internal with match none selector",
In: &v1.PodDisruptionBudget{
Spec: v1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpExists,
},
},
},
},
},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpExists,
},
},
},
},
},
},
{
Name: "v1 to internal with nil selector",
In: &v1.PodDisruptionBudget{},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{},
},
{
Name: "v1 to internal with match all selector",
In: &v1.PodDisruptionBudget{
Spec: v1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpDoesNotExist,
},
},
},
},
},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{},
},
},
},
},
}
scheme := runtime.NewScheme()
if err := policy.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
if err := AddToScheme(scheme); err != nil {
t.Fatal(err)
}
for _, tc := range testcases {
t.Run(tc.Name, func(t *testing.T) {
err := scheme.Convert(tc.In, tc.Out, nil)
if err != nil {
if len(tc.ExpectErr) == 0 {
t.Fatalf("unexpected error %v", err)
}
if !strings.Contains(err.Error(), tc.ExpectErr) {
t.Fatalf("expected error %s, got %v", tc.ExpectErr, err)
}
return
}
if len(tc.ExpectErr) > 0 {
t.Fatalf("expected error %s, got none", tc.ExpectErr)
}
if !reflect.DeepEqual(tc.Out, tc.ExpectOut) {
t.Fatalf("unexpected result:\n %s", cmp.Diff(tc.ExpectOut, tc.Out))
}
})
}
}

24
pkg/apis/policy/v1/doc.go Normal file
View File

@ -0,0 +1,24 @@
/*
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.
*/
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/policy
// +k8s:conversion-gen-external-types=k8s.io/api/policy/v1
// +k8s:defaulter-gen=TypeMeta
// +k8s:defaulter-gen-input=../../../../vendor/k8s.io/api/policy/v1
// Package policy is for any kind of policy object. Currently, this only
// includes policyv1.PodDisruptionBudget
package v1 // import "k8s.io/kubernetes/pkg/apis/policy/v1"

View File

@ -0,0 +1,45 @@
/*
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 (
policyv1 "k8s.io/api/policy/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "policy"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
localSchemeBuilder = &policyv1.SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(RegisterDefaults)
}

View File

@ -0,0 +1,207 @@
// +build !ignore_autogenerated
/*
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 conversion-gen. DO NOT EDIT.
package v1
import (
unsafe "unsafe"
v1 "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
intstr "k8s.io/apimachinery/pkg/util/intstr"
policy "k8s.io/kubernetes/pkg/apis/policy"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
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 {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.PodDisruptionBudgetList)(nil), (*policy.PodDisruptionBudgetList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(a.(*v1.PodDisruptionBudgetList), b.(*policy.PodDisruptionBudgetList), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.PodDisruptionBudgetList)(nil), (*v1.PodDisruptionBudgetList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_PodDisruptionBudgetList_To_v1_PodDisruptionBudgetList(a.(*policy.PodDisruptionBudgetList), b.(*v1.PodDisruptionBudgetList), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.PodDisruptionBudgetSpec)(nil), (*policy.PodDisruptionBudgetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(a.(*v1.PodDisruptionBudgetSpec), b.(*policy.PodDisruptionBudgetSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.PodDisruptionBudgetSpec)(nil), (*v1.PodDisruptionBudgetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(a.(*policy.PodDisruptionBudgetSpec), b.(*v1.PodDisruptionBudgetSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1.PodDisruptionBudgetStatus)(nil), (*policy.PodDisruptionBudgetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus(a.(*v1.PodDisruptionBudgetStatus), b.(*policy.PodDisruptionBudgetStatus), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.PodDisruptionBudgetStatus)(nil), (*v1.PodDisruptionBudgetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus(a.(*policy.PodDisruptionBudgetStatus), b.(*v1.PodDisruptionBudgetStatus), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*v1.PodDisruptionBudget)(nil), (*policy.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1_PodDisruptionBudget_To_policy_PodDisruptionBudget(a.(*v1.PodDisruptionBudget), b.(*policy.PodDisruptionBudget), scope)
}); err != nil {
return err
}
return nil
}
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 {
return err
}
if err := Convert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func autoConvert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget(in *policy.PodDisruptionBudget, out *v1.PodDisruptionBudget, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget is an autogenerated conversion function.
func Convert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget(in *policy.PodDisruptionBudget, out *v1.PodDisruptionBudget, s conversion.Scope) error {
return autoConvert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget(in, out, s)
}
func autoConvert_v1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in *v1.PodDisruptionBudgetList, out *policy.PodDisruptionBudgetList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]policy.PodDisruptionBudget, len(*in))
for i := range *in {
if err := Convert_v1_PodDisruptionBudget_To_policy_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
// Convert_v1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList is an autogenerated conversion function.
func Convert_v1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in *v1.PodDisruptionBudgetList, out *policy.PodDisruptionBudgetList, s conversion.Scope) error {
return autoConvert_v1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in, out, s)
}
func autoConvert_policy_PodDisruptionBudgetList_To_v1_PodDisruptionBudgetList(in *policy.PodDisruptionBudgetList, out *v1.PodDisruptionBudgetList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]v1.PodDisruptionBudget, len(*in))
for i := range *in {
if err := Convert_policy_PodDisruptionBudget_To_v1_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
// Convert_policy_PodDisruptionBudgetList_To_v1_PodDisruptionBudgetList is an autogenerated conversion function.
func Convert_policy_PodDisruptionBudgetList_To_v1_PodDisruptionBudgetList(in *policy.PodDisruptionBudgetList, out *v1.PodDisruptionBudgetList, s conversion.Scope) error {
return autoConvert_policy_PodDisruptionBudgetList_To_v1_PodDisruptionBudgetList(in, out, s)
}
func autoConvert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(in *v1.PodDisruptionBudgetSpec, out *policy.PodDisruptionBudgetSpec, s conversion.Scope) error {
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
return nil
}
// Convert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec is an autogenerated conversion function.
func Convert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(in *v1.PodDisruptionBudgetSpec, out *policy.PodDisruptionBudgetSpec, s conversion.Scope) error {
return autoConvert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(in, out, s)
}
func autoConvert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(in *policy.PodDisruptionBudgetSpec, out *v1.PodDisruptionBudgetSpec, s conversion.Scope) error {
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
return nil
}
// Convert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec is an autogenerated conversion function.
func Convert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(in *policy.PodDisruptionBudgetSpec, out *v1.PodDisruptionBudgetSpec, s conversion.Scope) error {
return autoConvert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(in, out, s)
}
func autoConvert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus(in *v1.PodDisruptionBudgetStatus, out *policy.PodDisruptionBudgetStatus, s conversion.Scope) error {
out.ObservedGeneration = in.ObservedGeneration
out.DisruptedPods = *(*map[string]metav1.Time)(unsafe.Pointer(&in.DisruptedPods))
out.DisruptionsAllowed = in.DisruptionsAllowed
out.CurrentHealthy = in.CurrentHealthy
out.DesiredHealthy = in.DesiredHealthy
out.ExpectedPods = in.ExpectedPods
out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions))
return nil
}
// Convert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus is an autogenerated conversion function.
func Convert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus(in *v1.PodDisruptionBudgetStatus, out *policy.PodDisruptionBudgetStatus, s conversion.Scope) error {
return autoConvert_v1_PodDisruptionBudgetStatus_To_policy_PodDisruptionBudgetStatus(in, out, s)
}
func autoConvert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus(in *policy.PodDisruptionBudgetStatus, out *v1.PodDisruptionBudgetStatus, s conversion.Scope) error {
out.ObservedGeneration = in.ObservedGeneration
out.DisruptedPods = *(*map[string]metav1.Time)(unsafe.Pointer(&in.DisruptedPods))
out.DisruptionsAllowed = in.DisruptionsAllowed
out.CurrentHealthy = in.CurrentHealthy
out.DesiredHealthy = in.DesiredHealthy
out.ExpectedPods = in.ExpectedPods
out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions))
return nil
}
// Convert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus is an autogenerated conversion function.
func Convert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus(in *policy.PodDisruptionBudgetStatus, out *v1.PodDisruptionBudgetStatus, s conversion.Scope) error {
return autoConvert_policy_PodDisruptionBudgetStatus_To_v1_PodDisruptionBudgetStatus(in, out, s)
}

View File

@ -0,0 +1,32 @@
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@ -0,0 +1,66 @@
/*
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 v1beta1
import (
"k8s.io/api/policy/v1beta1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/kubernetes/pkg/apis/policy"
)
func Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *v1beta1.PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error {
if err := autoConvert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in, out, s); err != nil {
return err
}
switch {
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.V1beta1MatchNoneSelector):
// If the v1beta1 version has a non-nil but empty selector, it should be
// selecting no pods, even when used with the internal or v1 api. We
// add a selector that is non-empty but will never match any pods.
out.Spec.Selector = policy.NonV1beta1MatchNoneSelector.DeepCopy()
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.V1beta1MatchAllSelector):
// If the v1beta1 version has our v1beta1-specific "match-all" selector,
// swap that out for a simpler empty "match-all" selector for v1
out.Spec.Selector = policy.NonV1beta1MatchAllSelector.DeepCopy()
default:
// otherwise, make sure the label intended to be used in a match-all or match-none selector
// never gets combined with user-specified fields
policy.StripPDBV1beta1Label(out.Spec.Selector)
}
return nil
}
func Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in *policy.PodDisruptionBudget, out *v1beta1.PodDisruptionBudget, s conversion.Scope) error {
if err := autoConvert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in, out, s); err != nil {
return err
}
switch {
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.NonV1beta1MatchNoneSelector):
// If the internal version has our v1beta1-specific "match-none" selector,
// swap that out for a simpler empty "match-none" selector for v1beta1
out.Spec.Selector = policy.V1beta1MatchNoneSelector.DeepCopy()
case apiequality.Semantic.DeepEqual(in.Spec.Selector, policy.NonV1beta1MatchAllSelector):
// If the internal version has a non-nil but empty selector, we want it to
// select all pods. We make sure this happens even with the v1beta1 api by
// adding a non-empty selector that selects all pods.
out.Spec.Selector = policy.V1beta1MatchAllSelector.DeepCopy()
}
return nil
}

View File

@ -0,0 +1,197 @@
/*
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 v1beta1
import (
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/api/policy/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/apis/policy"
)
func TestConversion(t *testing.T) {
testcases := []struct {
Name string
In runtime.Object
Out runtime.Object
ExpectOut runtime.Object
ExpectErr string
}{
{
Name: "v1beta1 to internal with empty selector",
In: &v1beta1.PodDisruptionBudget{
Spec: v1beta1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{},
},
},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpExists,
},
},
},
},
},
},
{
Name: "v1beta1 to internal with nil selector",
In: &v1beta1.PodDisruptionBudget{},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{},
},
{
Name: "v1 to internal with existing selector",
In: &v1beta1.PodDisruptionBudget{
Spec: v1beta1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
},
},
},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
},
},
},
},
{
Name: "v1beta1 to internal with existing pdb selector",
In: &v1beta1.PodDisruptionBudget{
Spec: v1beta1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpDoesNotExist,
},
},
},
},
},
Out: &policy.PodDisruptionBudget{},
ExpectOut: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
MatchExpressions: []metav1.LabelSelectorRequirement{},
},
},
},
},
{
Name: "internal to v1beta1 with empty selector",
In: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{},
},
},
Out: &v1beta1.PodDisruptionBudget{},
ExpectOut: &v1beta1.PodDisruptionBudget{
Spec: v1beta1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "pdb.kubernetes.io/deprecated-v1beta1-empty-selector-match",
Operator: metav1.LabelSelectorOpDoesNotExist,
},
},
},
},
},
},
{
Name: "internal to v1beta1 with nil selector",
In: &policy.PodDisruptionBudget{},
Out: &v1beta1.PodDisruptionBudget{},
ExpectOut: &v1beta1.PodDisruptionBudget{},
},
{
Name: "internal to v1beta1 with existing selector",
In: &policy.PodDisruptionBudget{
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
},
},
},
Out: &v1beta1.PodDisruptionBudget{},
ExpectOut: &v1beta1.PodDisruptionBudget{
Spec: v1beta1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"foo": "bar",
},
},
},
},
},
}
scheme := runtime.NewScheme()
if err := policy.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
if err := AddToScheme(scheme); err != nil {
t.Fatal(err)
}
for _, tc := range testcases {
t.Run(tc.Name, func(t *testing.T) {
err := scheme.Convert(tc.In, tc.Out, nil)
if err != nil {
if len(tc.ExpectErr) == 0 {
t.Fatalf("unexpected error %v", err)
}
if !strings.Contains(err.Error(), tc.ExpectErr) {
t.Fatalf("expected error %s, got %v", tc.ExpectErr, err)
}
return
}
if len(tc.ExpectErr) > 0 {
t.Fatalf("expected error %s, got none", tc.ExpectErr)
}
if !reflect.DeepEqual(tc.Out, tc.ExpectOut) {
t.Fatalf("unexpected result:\n %s", cmp.Diff(tc.ExpectOut, tc.Out))
}
})
}
}

View File

@ -110,16 +110,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1beta1.PodDisruptionBudget)(nil), (*policy.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(a.(*v1beta1.PodDisruptionBudget), b.(*policy.PodDisruptionBudget), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*policy.PodDisruptionBudget)(nil), (*v1beta1.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(a.(*policy.PodDisruptionBudget), b.(*v1beta1.PodDisruptionBudget), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1beta1.PodDisruptionBudgetList)(nil), (*policy.PodDisruptionBudgetList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(a.(*v1beta1.PodDisruptionBudgetList), b.(*policy.PodDisruptionBudgetList), scope)
}); err != nil {
@ -230,6 +220,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*policy.PodDisruptionBudget)(nil), (*v1beta1.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(a.(*policy.PodDisruptionBudget), b.(*v1beta1.PodDisruptionBudget), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*v1beta1.PodDisruptionBudget)(nil), (*policy.PodDisruptionBudget)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(a.(*v1beta1.PodDisruptionBudget), b.(*policy.PodDisruptionBudget), scope)
}); err != nil {
return err
}
return nil
}
@ -394,11 +394,6 @@ func autoConvert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *v
return nil
}
// Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget is an autogenerated conversion function.
func Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in *v1beta1.PodDisruptionBudget, out *policy.PodDisruptionBudget, s conversion.Scope) error {
return autoConvert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(in, out, s)
}
func autoConvert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in *policy.PodDisruptionBudget, out *v1beta1.PodDisruptionBudget, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_policy_PodDisruptionBudgetSpec_To_v1beta1_PodDisruptionBudgetSpec(&in.Spec, &out.Spec, s); err != nil {
@ -410,14 +405,19 @@ func autoConvert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in *p
return nil
}
// Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget is an autogenerated conversion function.
func Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in *policy.PodDisruptionBudget, out *v1beta1.PodDisruptionBudget, s conversion.Scope) error {
return autoConvert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(in, out, s)
}
func autoConvert_v1beta1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(in *v1beta1.PodDisruptionBudgetList, out *policy.PodDisruptionBudgetList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]policy.PodDisruptionBudget)(unsafe.Pointer(&in.Items))
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]policy.PodDisruptionBudget, len(*in))
for i := range *in {
if err := Convert_v1beta1_PodDisruptionBudget_To_policy_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
@ -428,7 +428,17 @@ func Convert_v1beta1_PodDisruptionBudgetList_To_policy_PodDisruptionBudgetList(i
func autoConvert_policy_PodDisruptionBudgetList_To_v1beta1_PodDisruptionBudgetList(in *policy.PodDisruptionBudgetList, out *v1beta1.PodDisruptionBudgetList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]v1beta1.PodDisruptionBudget)(unsafe.Pointer(&in.Items))
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]v1beta1.PodDisruptionBudget, len(*in))
for i := range *in {
if err := Convert_policy_PodDisruptionBudget_To_v1beta1_PodDisruptionBudget(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}

View File

@ -25,7 +25,7 @@ import (
apps "k8s.io/api/apps/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
policy "k8s.io/api/policy/v1beta1"
policy "k8s.io/api/policy/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
@ -38,13 +38,13 @@ import (
"k8s.io/client-go/discovery"
appsv1informers "k8s.io/client-go/informers/apps/v1"
coreinformers "k8s.io/client-go/informers/core/v1"
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
policyinformers "k8s.io/client-go/informers/policy/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
appsv1listers "k8s.io/client-go/listers/apps/v1"
corelisters "k8s.io/client-go/listers/core/v1"
policylisters "k8s.io/client-go/listers/policy/v1beta1"
policylisters "k8s.io/client-go/listers/policy/v1"
scaleclient "k8s.io/client-go/scale"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
@ -506,9 +506,6 @@ func (dc *DisruptionController) getPodsForPdb(pdb *policy.PodDisruptionBudget) (
if err != nil {
return []*v1.Pod{}, err
}
if sel.Empty() {
return []*v1.Pod{}, nil
}
pods, err := dc.podLister.Pods(pdb.Namespace).List(sel)
if err != nil {
return []*v1.Pod{}, err
@ -835,6 +832,6 @@ func (dc *DisruptionController) updatePdbStatus(pdb *policy.PodDisruptionBudget,
func (dc *DisruptionController) writePdbStatus(pdb *policy.PodDisruptionBudget) error {
// If this update fails, don't retry it. Allow the failure to get handled &
// retried in `processNextWorkItem()`.
_, err := dc.kubeClient.PolicyV1beta1().PodDisruptionBudgets(pdb.Namespace).UpdateStatus(context.TODO(), pdb, metav1.UpdateOptions{})
_, err := dc.kubeClient.PolicyV1().PodDisruptionBudgets(pdb.Namespace).UpdateStatus(context.TODO(), pdb, metav1.UpdateOptions{})
return err
}

View File

@ -29,7 +29,7 @@ import (
apps "k8s.io/api/apps/v1"
autoscalingapi "k8s.io/api/autoscaling/v1"
v1 "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1"
policy "k8s.io/api/policy/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
@ -151,7 +151,7 @@ func newFakeDisruptionController() (*disruptionController, *pdbStates) {
dc := NewDisruptionController(
informerFactory.Core().V1().Pods(),
informerFactory.Policy().V1beta1().PodDisruptionBudgets(),
informerFactory.Policy().V1().PodDisruptionBudgets(),
informerFactory.Core().V1().ReplicationControllers(),
informerFactory.Apps().V1().ReplicaSets(),
informerFactory.Apps().V1().Deployments(),
@ -175,7 +175,7 @@ func newFakeDisruptionController() (*disruptionController, *pdbStates) {
return &disruptionController{
dc,
informerFactory.Core().V1().Pods().Informer().GetStore(),
informerFactory.Policy().V1beta1().PodDisruptionBudgets().Informer().GetStore(),
informerFactory.Policy().V1().PodDisruptionBudgets().Informer().GetStore(),
informerFactory.Core().V1().ReplicationControllers().Informer().GetStore(),
informerFactory.Apps().V1().ReplicaSets().Informer().GetStore(),
informerFactory.Apps().V1().Deployments().Informer().GetStore(),
@ -402,7 +402,7 @@ func add(t *testing.T, store cache.Store, obj interface{}) {
}
}
// Create one with no selector. Verify it matches 0 pods.
// Create one with no selector. Verify it matches all pods
func TestNoSelector(t *testing.T) {
dc, ps := newFakeDisruptionController()
@ -416,7 +416,7 @@ func TestNoSelector(t *testing.T) {
add(t, dc.podStore, pod)
dc.sync(pdbName)
ps.VerifyPdbStatus(t, pdbName, 0, 0, 3, 0, map[string]metav1.Time{})
ps.VerifyPdbStatus(t, pdbName, 0, 1, 3, 1, map[string]metav1.Time{})
}
// Verify that available/expected counts go up as we add pods, then verify that
@ -1151,7 +1151,7 @@ func TestUpdatePDBStatusRetries(t *testing.T) {
// Create a PDB and 3 pods that match it.
pdb, pdbKey := newMinAvailablePodDisruptionBudget(t, intstr.FromInt(1))
pdb, err := dc.coreClient.PolicyV1beta1().PodDisruptionBudgets(pdb.Namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
pdb, err := dc.coreClient.PolicyV1().PodDisruptionBudgets(pdb.Namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Failed to create PDB: %v", err)
}
@ -1186,7 +1186,7 @@ func TestUpdatePDBStatusRetries(t *testing.T) {
// These GVRs are copied from the generated fake code because they are not exported.
var (
podsResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1beta1", Resource: "poddisruptionbudgets"}
poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "poddisruptionbudgets"}
)
// Bypass the coreClient.Fake and write directly to the ObjectTracker, because
@ -1248,7 +1248,7 @@ func TestUpdatePDBStatusRetries(t *testing.T) {
// (C) Whether or not sync() returned an error, the PDB status should reflect
// the evictions that took place.
finalPDB, err := dc.coreClient.PolicyV1beta1().PodDisruptionBudgets("default").Get(context.TODO(), pdb.Name, metav1.GetOptions{})
finalPDB, err := dc.coreClient.PolicyV1().PodDisruptionBudgets("default").Get(context.TODO(), pdb.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Failed to get PDB: %v", err)
}

View File

@ -54,6 +54,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyapiv1 "k8s.io/api/policy/v1"
policyapiv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -688,6 +689,7 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
networkingapiv1beta1.SchemeGroupVersion,
nodev1.SchemeGroupVersion,
nodev1beta1.SchemeGroupVersion,
policyapiv1.SchemeGroupVersion,
policyapiv1beta1.SchemeGroupVersion,
rbacv1.SchemeGroupVersion,
rbacv1beta1.SchemeGroupVersion,

View File

@ -77,6 +77,7 @@ var GVRToStorageVersionHash = map[string]string{
"networking.k8s.io/v1/ingressclasses": "l/iqIbDgFyQ=",
"node.k8s.io/v1/runtimeclasses": "WQTu1GL3T2Q=",
"node.k8s.io/v1beta1/runtimeclasses": "WQTu1GL3T2Q=",
"policy/v1/poddisruptionbudgets": "6BGBu0kpHtk=",
"policy/v1beta1/poddisruptionbudgets": "6BGBu0kpHtk=",
"policy/v1beta1/podsecuritypolicies": "khBLobUXkqA=",
"rbac.authorization.k8s.io/v1/clusterrolebindings": "48tpQ8gZHFc=",

View File

@ -811,7 +811,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
WindowsEndpointSliceProxying: {Default: true, PreRelease: featuregate.Beta},
StartupProbe: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
AllowInsecureBackendProxy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.23
PodDisruptionBudget: {Default: true, PreRelease: featuregate.Beta},
PodDisruptionBudget: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.25
CronJobControllerV2: {Default: true, PreRelease: featuregate.Beta},
DaemonSetUpdateSurge: {Default: false, PreRelease: featuregate.Alpha},
ServiceTopology: {Default: false, PreRelease: featuregate.Alpha},

View File

@ -22,7 +22,7 @@ import (
"reflect"
"time"
policyv1beta1 "k8s.io/api/policy/v1beta1"
policyv1 "k8s.io/api/policy/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@ -31,7 +31,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/util/dryrun"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
"k8s.io/client-go/util/retry"
pdbhelper "k8s.io/component-helpers/apps/poddisruptionbudget"
podutil "k8s.io/kubernetes/pkg/api/pod"
@ -314,7 +314,7 @@ func createTooManyRequestsError(name string) error {
}
// checkAndDecrement checks if the provided PodDisruptionBudget allows any disruption.
func (r *EvictionREST) checkAndDecrement(namespace string, podName string, pdb policyv1beta1.PodDisruptionBudget, dryRun bool) error {
func (r *EvictionREST) checkAndDecrement(namespace string, podName string, pdb policyv1.PodDisruptionBudget, dryRun bool) error {
if pdb.Status.ObservedGeneration < pdb.Generation {
return createTooManyRequestsError(pdb.Name)
@ -358,17 +358,13 @@ func (r *EvictionREST) checkAndDecrement(namespace string, podName string, pdb p
}
// getPodDisruptionBudgets returns any PDBs that match the pod or err if there's an error.
func (r *EvictionREST) getPodDisruptionBudgets(ctx context.Context, pod *api.Pod) ([]policyv1beta1.PodDisruptionBudget, error) {
if len(pod.Labels) == 0 {
return nil, nil
}
func (r *EvictionREST) getPodDisruptionBudgets(ctx context.Context, pod *api.Pod) ([]policyv1.PodDisruptionBudget, error) {
pdbList, err := r.podDisruptionBudgetClient.PodDisruptionBudgets(pod.Namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}
var pdbs []policyv1beta1.PodDisruptionBudget
var pdbs []policyv1.PodDisruptionBudget
for _, pdb := range pdbList.Items {
if pdb.Namespace != pod.Namespace {
continue

View File

@ -21,7 +21,7 @@ import (
"errors"
"testing"
policyv1beta1 "k8s.io/api/policy/v1beta1"
policyv1 "k8s.io/api/policy/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
@ -52,10 +52,10 @@ func TestEviction(t *testing.T) {
}{
{
name: "matching pdbs with no disruptions allowed, pod running",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t1", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: true,
@ -64,10 +64,10 @@ func TestEviction(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod pending",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t2", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: false,
@ -77,10 +77,10 @@ func TestEviction(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod succeeded",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t3", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: false,
@ -90,10 +90,10 @@ func TestEviction(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod failed",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t4", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: false,
@ -103,10 +103,10 @@ func TestEviction(t *testing.T) {
},
{
name: "matching pdbs with disruptions allowed",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t5", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectDeleted: true,
@ -114,10 +114,10 @@ func TestEviction(t *testing.T) {
},
{
name: "non-matching pdbs",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"b": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"b": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t6", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectDeleted: true,
@ -125,10 +125,10 @@ func TestEviction(t *testing.T) {
},
{
name: "matching pdbs with disruptions allowed but bad name in Url",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
}},
badNameInURL: true,
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t7", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
@ -161,7 +161,7 @@ func TestEviction(t *testing.T) {
}
client := fake.NewSimpleClientset(tc.pdbs...)
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1beta1())
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1())
name := pod.Name
if tc.badNameInURL {
@ -225,10 +225,10 @@ func TestEvictionIngorePDB(t *testing.T) {
}{
{
name: "pdbs No disruptions allowed, pod pending, first delete conflict, pod still pending, pod deleted successfully",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t1", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: false,
@ -241,10 +241,10 @@ func TestEvictionIngorePDB(t *testing.T) {
// pod should not be deleted.
{
name: "pdbs No disruptions allowed, pod pending, first delete conflict, pod becomes running, continueToPDBs",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t2", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: true,
@ -254,10 +254,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "pdbs disruptions allowed, pod pending, first delete conflict, pod becomes running, continueToPDBs",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t3", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: false,
@ -267,10 +267,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "pod pending, always conflict on delete",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t4", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
expectError: true,
@ -280,10 +280,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "pod pending, always conflict on delete, user provided ResourceVersion constraint",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t5", Namespace: "default"}, DeleteOptions: metav1.NewRVDeletionPrecondition("userProvided")},
expectError: true,
@ -293,10 +293,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod terminating",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
}},
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t6", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(300)},
expectError: false,
@ -306,10 +306,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod running, pod healthy, unhealthy pod not ours",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
// This simulates 3 pods desired, our pod healthy, unhealthy pod is not ours.
DisruptionsAllowed: 0,
CurrentHealthy: 2,
@ -329,10 +329,10 @@ func TestEvictionIngorePDB(t *testing.T) {
},
{
name: "matching pdbs with no disruptions allowed, pod running, pod unhealthy, unhealthy pod ours",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
// This simulates 3 pods desired, our pod unhealthy
DisruptionsAllowed: 0,
CurrentHealthy: 2,
@ -353,10 +353,10 @@ func TestEvictionIngorePDB(t *testing.T) {
{
// This case should return the 529 retry error.
name: "matching pdbs with no disruptions allowed, pod running, pod unhealthy, unhealthy pod ours, resource version conflict",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
// This simulates 3 pods desired, our pod unhealthy
DisruptionsAllowed: 0,
CurrentHealthy: 2,
@ -377,10 +377,10 @@ func TestEvictionIngorePDB(t *testing.T) {
{
// This case should return the 529 retry error.
name: "matching pdbs with no disruptions allowed, pod running, pod unhealthy, unhealthy pod ours, other error on delete",
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
// This simulates 3 pods desired, our pod unhealthy
DisruptionsAllowed: 0,
CurrentHealthy: 2,
@ -428,7 +428,7 @@ func TestEvictionIngorePDB(t *testing.T) {
}
client := fake.NewSimpleClientset(tc.pdbs...)
evictionRest := newEvictionStorage(ms, client.PolicyV1beta1())
evictionRest := newEvictionStorage(ms, client.PolicyV1())
name := pod.Name
ms.pod = pod
@ -473,10 +473,10 @@ func TestEvictionDryRun(t *testing.T) {
name: "with pdbs",
evictionOptions: &metav1.DeleteOptions{DryRun: []string{"All"}},
requestOptions: &metav1.CreateOptions{DryRun: []string{"All"}},
pdbs: []runtime.Object{&policyv1beta1.PodDisruptionBudget{
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
}},
},
}
@ -496,7 +496,7 @@ func TestEvictionDryRun(t *testing.T) {
}
client := fake.NewSimpleClientset(tc.pdbs...)
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1beta1())
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1())
eviction := &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}, DeleteOptions: tc.evictionOptions}
_, err := evictionRest.Create(testContext, pod.Name, eviction, nil, tc.requestOptions)
if err != nil {
@ -509,47 +509,47 @@ func TestEvictionDryRun(t *testing.T) {
func TestEvictionPDBStatus(t *testing.T) {
testcases := []struct {
name string
pdb *policyv1beta1.PodDisruptionBudget
pdb *policyv1.PodDisruptionBudget
expectedDisruptionsAllowed int32
expectedReason string
}{
{
name: "pdb status is updated after eviction",
pdb: &policyv1beta1.PodDisruptionBudget{
pdb: &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
DisruptionsAllowed: 1,
Conditions: []metav1.Condition{
{
Type: policyv1beta1.DisruptionAllowedCondition,
Reason: policyv1beta1.SufficientPodsReason,
Type: policyv1.DisruptionAllowedCondition,
Reason: policyv1.SufficientPodsReason,
Status: metav1.ConditionTrue,
},
},
},
},
expectedDisruptionsAllowed: 0,
expectedReason: policyv1beta1.InsufficientPodsReason,
expectedReason: policyv1.InsufficientPodsReason,
},
{
name: "condition reason is only updated if AllowedDisruptions becomes 0",
pdb: &policyv1beta1.PodDisruptionBudget{
pdb: &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: policyv1beta1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1beta1.PodDisruptionBudgetStatus{
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
Status: policyv1.PodDisruptionBudgetStatus{
DisruptionsAllowed: 3,
Conditions: []metav1.Condition{
{
Type: policyv1beta1.DisruptionAllowedCondition,
Reason: policyv1beta1.SufficientPodsReason,
Type: policyv1.DisruptionAllowedCondition,
Reason: policyv1.SufficientPodsReason,
Status: metav1.ConditionTrue,
},
},
},
},
expectedDisruptionsAllowed: 2,
expectedReason: policyv1beta1.SufficientPodsReason,
expectedReason: policyv1.SufficientPodsReason,
},
}
@ -578,14 +578,14 @@ func TestEvictionPDBStatus(t *testing.T) {
}
}
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1beta1())
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1())
eviction := &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "foo-1", Namespace: "default"}, DeleteOptions: &metav1.DeleteOptions{}}
_, err := evictionRest.Create(testContext, "foo-1", eviction, nil, &metav1.CreateOptions{})
if err != nil {
t.Fatalf("Failed to run eviction: %v", err)
}
existingPDB, err := client.PolicyV1beta1().PodDisruptionBudgets(metav1.NamespaceDefault).Get(context.TODO(), tc.pdb.Name, metav1.GetOptions{})
existingPDB, err := client.PolicyV1().PodDisruptionBudgets(metav1.NamespaceDefault).Get(context.TODO(), tc.pdb.Name, metav1.GetOptions{})
if err != nil {
t.Errorf("%#v", err)
return
@ -595,7 +595,7 @@ func TestEvictionPDBStatus(t *testing.T) {
t.Errorf("expected DisruptionsAllowed to be %d, but got %d", want, got)
}
cond := apimeta.FindStatusCondition(existingPDB.Status.Conditions, policyv1beta1.DisruptionAllowedCondition)
cond := apimeta.FindStatusCondition(existingPDB.Status.Conditions, policyv1.DisruptionAllowedCondition)
if want, got := tc.expectedReason, cond.Reason; want != got {
t.Errorf("expected Reason to be %q, but got %q", want, got)
}

View File

@ -33,7 +33,7 @@ import (
storeerr "k8s.io/apiserver/pkg/storage/errors"
"k8s.io/apiserver/pkg/util/dryrun"
utilfeature "k8s.io/apiserver/pkg/util/feature"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
podutil "k8s.io/kubernetes/pkg/api/pod"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"

View File

@ -35,7 +35,7 @@ import (
serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/storage/etcd3"
utilfeature "k8s.io/apiserver/pkg/util/feature"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
@ -110,13 +110,9 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
NegotiatedSerializer: legacyscheme.Codecs,
}
var podDisruptionClient policyclient.PodDisruptionBudgetsGetter
if policyGroupVersion := (schema.GroupVersion{Group: "policy", Version: "v1beta1"}); legacyscheme.Scheme.IsVersionRegistered(policyGroupVersion) {
var err error
podDisruptionClient, err = policyclient.NewForConfig(c.LoopbackClientConfig)
if err != nil {
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err
}
podDisruptionClient, err := policyclient.NewForConfig(c.LoopbackClientConfig)
if err != nil {
return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err
}
restStorage := LegacyRESTStorage{}

View File

@ -114,8 +114,8 @@ func (podDisruptionBudgetStatusStrategy) ValidateUpdate(ctx context.Context, obj
var apiVersion schema.GroupVersion
if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
apiVersion = schema.GroupVersion{
Group: requestInfo.APIVersion,
Version: requestInfo.APIGroup,
Group: requestInfo.APIGroup,
Version: requestInfo.APIVersion,
}
}
return validation.ValidatePodDisruptionBudgetStatusUpdate(obj.(*policy.PodDisruptionBudget).Status,

View File

@ -148,3 +148,65 @@ func TestPodDisruptionBudgetStatusStrategy(t *testing.T) {
t.Errorf("Unexpected error %v", errs)
}
}
func TestPodDisruptionBudgetStatusValidationByApiVersion(t *testing.T) {
testCases := map[string]struct {
apiVersion string
validation bool
}{
"policy/v1beta1 should not do update validation": {
apiVersion: "v1beta1",
validation: false,
},
"policy/v1 should do update validation": {
apiVersion: "v1",
validation: true,
},
"policy/some-version should do update validation": {
apiVersion: "some-version",
validation: true,
},
}
for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) {
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(),
&genericapirequest.RequestInfo{
APIGroup: "policy",
APIVersion: tc.apiVersion,
})
oldMaxUnavailable := intstr.FromInt(2)
newMaxUnavailable := intstr.FromInt(3)
oldPdb := &policy.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "10"},
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
MaxUnavailable: &oldMaxUnavailable,
},
Status: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: 1,
},
}
newPdb := &policy.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "9"},
Spec: policy.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
MinAvailable: &newMaxUnavailable,
},
Status: policy.PodDisruptionBudgetStatus{
DisruptionsAllowed: -1, // This is not allowed, so should trigger validation error.
},
}
errs := StatusStrategy.ValidateUpdate(ctx, newPdb, oldPdb)
hasErrors := len(errs) > 0
if !tc.validation && hasErrors {
t.Errorf("Validation failed when no validation should happen")
}
if tc.validation && !hasErrors {
t.Errorf("Expected validation errors but didn't get any")
}
})
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package rest
import (
policyapiv1 "k8s.io/api/policy/v1"
policyapiv1beta1 "k8s.io/api/policy/v1beta1"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
@ -42,6 +43,14 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag
apiGroupInfo.VersionedResourcesStorageMap[policyapiv1beta1.SchemeGroupVersion.Version] = storageMap
}
}
if apiResourceConfigSource.VersionEnabled(policyapiv1.SchemeGroupVersion) {
if storageMap, err := p.v1Storage(apiResourceConfigSource, restOptionsGetter); err != nil {
return genericapiserver.APIGroupInfo{}, false, err
} else {
apiGroupInfo.VersionedResourcesStorageMap[policyapiv1.SchemeGroupVersion.Version] = storageMap
}
}
return apiGroupInfo, true, nil
}
@ -64,6 +73,19 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
return storage, err
}
func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
storage := map[string]rest.Storage{}
poddisruptionbudgetStorage, poddisruptionbudgetStatusStorage, err := poddisruptionbudgetstore.NewREST(restOptionsGetter)
if err != nil {
return storage, err
}
storage["poddisruptionbudgets"] = poddisruptionbudgetStorage
storage["poddisruptionbudgets/status"] = poddisruptionbudgetStatusStorage
return storage, err
}
func (p RESTStorageProvider) GroupName() string {
return policy.GroupName
}

View File

@ -29,7 +29,7 @@ import (
"k8s.io/klog/v2"
v1 "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1"
policy "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@ -37,7 +37,7 @@ import (
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
corelisters "k8s.io/client-go/listers/core/v1"
policylisters "k8s.io/client-go/listers/policy/v1beta1"
policylisters "k8s.io/client-go/listers/policy/v1"
corev1helpers "k8s.io/component-helpers/scheduling/corev1"
extenderv1 "k8s.io/kube-scheduler/extender/v1"
kubefeatures "k8s.io/kubernetes/pkg/features"
@ -799,7 +799,7 @@ func filterPodsWithPDBViolation(podInfos []*framework.PodInfo, pdbs []*policy.Po
func getPDBLister(informerFactory informers.SharedInformerFactory) policylisters.PodDisruptionBudgetLister {
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.PodDisruptionBudget) {
return informerFactory.Policy().V1beta1().PodDisruptionBudgets().Lister()
return informerFactory.Policy().V1().PodDisruptionBudgets().Lister()
}
return nil
}

View File

@ -27,7 +27,7 @@ import (
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1"
policy "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"

View File

@ -0,0 +1,24 @@
/*
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.
*/
// +k8s:deepcopy-gen=package
// +k8s:protobuf-gen=package
// +k8s:openapi-gen=true
// Package policy is for any kind of policy object. Suitable examples, even if
// they aren't all here, are PodDisruptionBudget, PodSecurityPolicy,
// NetworkPolicy, etc.
package v1 // import "k8s.io/api/policy/v1"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/*
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.
*/
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
syntax = "proto2";
package k8s.io.api.policy.v1;
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1";
// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods
message PodDisruptionBudget {
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
// Specification of the desired behavior of the PodDisruptionBudget.
// +optional
optional PodDisruptionBudgetSpec spec = 2;
// Most recently observed status of the PodDisruptionBudget.
// +optional
optional PodDisruptionBudgetStatus status = 3;
}
// PodDisruptionBudgetList is a collection of PodDisruptionBudgets.
message PodDisruptionBudgetList {
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
// Items is a list of PodDisruptionBudgets
repeated PodDisruptionBudget items = 2;
}
// PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.
message PodDisruptionBudgetSpec {
// An eviction is allowed if at least "minAvailable" pods selected by
// "selector" will still be available after the eviction, i.e. even in the
// absence of the evicted pod. So for example you can prevent all voluntary
// evictions by specifying "100%".
// +optional
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString minAvailable = 1;
// Label query over pods whose evictions are managed by the disruption
// budget.
// A null selector will match no pods, while an empty ({}) selector will select
// all pods within the namespace.
// +patchStrategy=replace
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2;
// An eviction is allowed if at most "maxUnavailable" pods selected by
// "selector" are unavailable after the eviction, i.e. even in absence of
// the evicted pod. For example, one can prevent all voluntary evictions
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
// +optional
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 3;
}
// PodDisruptionBudgetStatus represents information about the status of a
// PodDisruptionBudget. Status may trail the actual state of a system.
message PodDisruptionBudgetStatus {
// Most recent generation observed when updating this PDB status. DisruptionsAllowed and other
// status information is valid only if observedGeneration equals to PDB's object generation.
// +optional
optional int64 observedGeneration = 1;
// DisruptedPods contains information about pods whose eviction was
// processed by the API server eviction subresource handler but has not
// yet been observed by the PodDisruptionBudget controller.
// A pod will be in this map from the time when the API server processed the
// eviction request to the time when the pod is seen by PDB controller
// as having been marked for deletion (or after a timeout). The key in the map is the name of the pod
// and the value is the time when the API server processed the eviction request. If
// the deletion didn't occur and a pod is still there it will be removed from
// the list automatically by PodDisruptionBudget controller after some time.
// If everything goes smooth this map should be empty for the most of the time.
// Large number of entries in the map may indicate problems with pod deletions.
// +optional
map<string, k8s.io.apimachinery.pkg.apis.meta.v1.Time> disruptedPods = 2;
// Number of pod disruptions that are currently allowed.
optional int32 disruptionsAllowed = 3;
// current number of healthy pods
optional int32 currentHealthy = 4;
// minimum desired number of healthy pods
optional int32 desiredHealthy = 5;
// total number of pods counted by this disruption budget
optional int32 expectedPods = 6;
// Conditions contain conditions for PDB. The disruption controller sets the
// DisruptionAllowed condition. The following are known values for the reason field
// (additional reasons could be added in the future):
// - SyncFailed: The controller encountered an error and wasn't able to compute
// the number of allowed disruptions. Therefore no disruptions are
// allowed and the status of the condition will be False.
// - InsufficientPods: The number of pods are either at or below the number
// required by the PodDisruptionBudget. No disruptions are
// allowed and the status of the condition will be False.
// - SufficientPods: There are more pods than required by the PodDisruptionBudget.
// The condition will be True, and the number of allowed
// disruptions are provided by the disruptionsAllowed property.
//
// +optional
// +patchMergeKey=type
// +patchStrategy=merge
// +listType=map
// +listMapKey=type
repeated k8s.io.apimachinery.pkg.apis.meta.v1.Condition conditions = 7;
}

View File

@ -0,0 +1,51 @@
/*
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 (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "policy"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&PodDisruptionBudget{},
&PodDisruptionBudgetList{},
)
// Add the watch version that applies
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -0,0 +1,150 @@
/*
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 (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.
type PodDisruptionBudgetSpec struct {
// An eviction is allowed if at least "minAvailable" pods selected by
// "selector" will still be available after the eviction, i.e. even in the
// absence of the evicted pod. So for example you can prevent all voluntary
// evictions by specifying "100%".
// +optional
MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty" protobuf:"bytes,1,opt,name=minAvailable"`
// Label query over pods whose evictions are managed by the disruption
// budget.
// A null selector will match no pods, while an empty ({}) selector will select
// all pods within the namespace.
// +patchStrategy=replace
// +optional
Selector *metav1.LabelSelector `json:"selector,omitempty" patchStrategy:"replace" protobuf:"bytes,2,opt,name=selector"`
// An eviction is allowed if at most "maxUnavailable" pods selected by
// "selector" are unavailable after the eviction, i.e. even in absence of
// the evicted pod. For example, one can prevent all voluntary evictions
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,3,opt,name=maxUnavailable"`
}
// PodDisruptionBudgetStatus represents information about the status of a
// PodDisruptionBudget. Status may trail the actual state of a system.
type PodDisruptionBudgetStatus struct {
// Most recent generation observed when updating this PDB status. DisruptionsAllowed and other
// status information is valid only if observedGeneration equals to PDB's object generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"`
// DisruptedPods contains information about pods whose eviction was
// processed by the API server eviction subresource handler but has not
// yet been observed by the PodDisruptionBudget controller.
// A pod will be in this map from the time when the API server processed the
// eviction request to the time when the pod is seen by PDB controller
// as having been marked for deletion (or after a timeout). The key in the map is the name of the pod
// and the value is the time when the API server processed the eviction request. If
// the deletion didn't occur and a pod is still there it will be removed from
// the list automatically by PodDisruptionBudget controller after some time.
// If everything goes smooth this map should be empty for the most of the time.
// Large number of entries in the map may indicate problems with pod deletions.
// +optional
DisruptedPods map[string]metav1.Time `json:"disruptedPods,omitempty" protobuf:"bytes,2,rep,name=disruptedPods"`
// Number of pod disruptions that are currently allowed.
DisruptionsAllowed int32 `json:"disruptionsAllowed" protobuf:"varint,3,opt,name=disruptionsAllowed"`
// current number of healthy pods
CurrentHealthy int32 `json:"currentHealthy" protobuf:"varint,4,opt,name=currentHealthy"`
// minimum desired number of healthy pods
DesiredHealthy int32 `json:"desiredHealthy" protobuf:"varint,5,opt,name=desiredHealthy"`
// total number of pods counted by this disruption budget
ExpectedPods int32 `json:"expectedPods" protobuf:"varint,6,opt,name=expectedPods"`
// Conditions contain conditions for PDB. The disruption controller sets the
// DisruptionAllowed condition. The following are known values for the reason field
// (additional reasons could be added in the future):
// - SyncFailed: The controller encountered an error and wasn't able to compute
// the number of allowed disruptions. Therefore no disruptions are
// allowed and the status of the condition will be False.
// - InsufficientPods: The number of pods are either at or below the number
// required by the PodDisruptionBudget. No disruptions are
// allowed and the status of the condition will be False.
// - SufficientPods: There are more pods than required by the PodDisruptionBudget.
// The condition will be True, and the number of allowed
// disruptions are provided by the disruptionsAllowed property.
//
// +optional
// +patchMergeKey=type
// +patchStrategy=merge
// +listType=map
// +listMapKey=type
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,7,rep,name=conditions"`
}
const (
// DisruptionAllowedCondition is a condition set by the disruption controller
// that signal whether any of the pods covered by the PDB can be disrupted.
DisruptionAllowedCondition = "DisruptionAllowed"
// SyncFailedReason is set on the DisruptionAllowed condition if reconcile
// of the PDB failed and therefore disruption of pods are not allowed.
SyncFailedReason = "SyncFailed"
// SufficientPodsReason is set on the DisruptionAllowed condition if there are
// more pods covered by the PDB than required and at least one can be disrupted.
SufficientPodsReason = "SufficientPods"
// InsufficientPodsReason is set on the DisruptionAllowed condition if the number
// of pods are equal to or fewer than required by the PDB.
InsufficientPodsReason = "InsufficientPods"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods
type PodDisruptionBudget struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Specification of the desired behavior of the PodDisruptionBudget.
// +optional
Spec PodDisruptionBudgetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Most recently observed status of the PodDisruptionBudget.
// +optional
Status PodDisruptionBudgetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PodDisruptionBudgetList is a collection of PodDisruptionBudgets.
type PodDisruptionBudgetList struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Items is a list of PodDisruptionBudgets
Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@ -0,0 +1,77 @@
/*
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.
*/
package v1
// This file contains a collection of methods that can be used from go-restful to
// generate Swagger API documentation for its models. Please read this PR for more
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
//
// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
// they are on one line! For multiple line or blocks that you want to ignore use ---.
// Any context after a --- is ignored.
//
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
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",
"spec": "Specification of the desired behavior of the PodDisruptionBudget.",
"status": "Most recently observed status of the PodDisruptionBudget.",
}
func (PodDisruptionBudget) SwaggerDoc() map[string]string {
return map_PodDisruptionBudget
}
var map_PodDisruptionBudgetList = map[string]string{
"": "PodDisruptionBudgetList is a collection of PodDisruptionBudgets.",
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
"items": "Items is a list of PodDisruptionBudgets",
}
func (PodDisruptionBudgetList) SwaggerDoc() map[string]string {
return map_PodDisruptionBudgetList
}
var map_PodDisruptionBudgetSpec = map[string]string{
"": "PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.",
"minAvailable": "An eviction is allowed if at least \"minAvailable\" pods selected by \"selector\" will still be available after the eviction, i.e. even in the absence of the evicted pod. So for example you can prevent all voluntary evictions by specifying \"100%\".",
"selector": "Label query over pods whose evictions are managed by the disruption budget. A null selector will match no pods, while an empty ({}) selector will select all pods within the namespace.",
"maxUnavailable": "An eviction is allowed if at most \"maxUnavailable\" pods selected by \"selector\" are unavailable after the eviction, i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions by specifying 0. This is a mutually exclusive setting with \"minAvailable\".",
}
func (PodDisruptionBudgetSpec) SwaggerDoc() map[string]string {
return map_PodDisruptionBudgetSpec
}
var map_PodDisruptionBudgetStatus = map[string]string{
"": "PodDisruptionBudgetStatus represents information about the status of a PodDisruptionBudget. Status may trail the actual state of a system.",
"observedGeneration": "Most recent generation observed when updating this PDB status. DisruptionsAllowed and other status information is valid only if observedGeneration equals to PDB's object generation.",
"disruptedPods": "DisruptedPods contains information about pods whose eviction was processed by the API server eviction subresource handler but has not yet been observed by the PodDisruptionBudget controller. A pod will be in this map from the time when the API server processed the eviction request to the time when the pod is seen by PDB controller as having been marked for deletion (or after a timeout). The key in the map is the name of the pod and the value is the time when the API server processed the eviction request. If the deletion didn't occur and a pod is still there it will be removed from the list automatically by PodDisruptionBudget controller after some time. If everything goes smooth this map should be empty for the most of the time. Large number of entries in the map may indicate problems with pod deletions.",
"disruptionsAllowed": "Number of pod disruptions that are currently allowed.",
"currentHealthy": "current number of healthy pods",
"desiredHealthy": "minimum desired number of healthy pods",
"expectedPods": "total number of pods counted by this disruption budget",
"conditions": "Conditions contain conditions for PDB. The disruption controller sets the DisruptionAllowed condition. The following are known values for the reason field (additional reasons could be added in the future): - SyncFailed: The controller encountered an error and wasn't able to compute\n the number of allowed disruptions. Therefore no disruptions are\n allowed and the status of the condition will be False.\n- InsufficientPods: The number of pods are either at or below the number\n required by the PodDisruptionBudget. No disruptions are\n allowed and the status of the condition will be False.\n- SufficientPods: There are more pods than required by the PodDisruptionBudget.\n The condition will be True, and the number of allowed\n disruptions are provided by the disruptionsAllowed property.",
}
func (PodDisruptionBudgetStatus) SwaggerDoc() map[string]string {
return map_PodDisruptionBudgetStatus
}
// AUTO-GENERATED FUNCTIONS END HERE

View File

@ -0,0 +1,149 @@
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
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 *PodDisruptionBudget) DeepCopyInto(out *PodDisruptionBudget) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDisruptionBudget.
func (in *PodDisruptionBudget) DeepCopy() *PodDisruptionBudget {
if in == nil {
return nil
}
out := new(PodDisruptionBudget)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PodDisruptionBudget) 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 *PodDisruptionBudgetList) DeepCopyInto(out *PodDisruptionBudgetList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]PodDisruptionBudget, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDisruptionBudgetList.
func (in *PodDisruptionBudgetList) DeepCopy() *PodDisruptionBudgetList {
if in == nil {
return nil
}
out := new(PodDisruptionBudgetList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PodDisruptionBudgetList) 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 *PodDisruptionBudgetSpec) DeepCopyInto(out *PodDisruptionBudgetSpec) {
*out = *in
if in.MinAvailable != nil {
in, out := &in.MinAvailable, &out.MinAvailable
*out = new(intstr.IntOrString)
**out = **in
}
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = new(metav1.LabelSelector)
(*in).DeepCopyInto(*out)
}
if in.MaxUnavailable != nil {
in, out := &in.MaxUnavailable, &out.MaxUnavailable
*out = new(intstr.IntOrString)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDisruptionBudgetSpec.
func (in *PodDisruptionBudgetSpec) DeepCopy() *PodDisruptionBudgetSpec {
if in == nil {
return nil
}
out := new(PodDisruptionBudgetSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PodDisruptionBudgetStatus) DeepCopyInto(out *PodDisruptionBudgetStatus) {
*out = *in
if in.DisruptedPods != nil {
in, out := &in.DisruptedPods, &out.DisruptedPods
*out = make(map[string]metav1.Time, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]metav1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDisruptionBudgetStatus.
func (in *PodDisruptionBudgetStatus) DeepCopy() *PodDisruptionBudgetStatus {
if in == nil {
return nil
}
out := new(PodDisruptionBudgetStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -136,6 +136,10 @@ message PodDisruptionBudgetSpec {
// Label query over pods whose evictions are managed by the disruption
// budget.
// A null selector selects no pods.
// An empty selector ({}) also selects no pods, which differs from standard behavior of selecting all pods.
// In policy/v1, an empty selector will select all pods in the namespace.
// +patchStrategy=replace
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2;

View File

@ -33,8 +33,12 @@ type PodDisruptionBudgetSpec struct {
// Label query over pods whose evictions are managed by the disruption
// budget.
// A null selector selects no pods.
// An empty selector ({}) also selects no pods, which differs from standard behavior of selecting all pods.
// In policy/v1, an empty selector will select all pods in the namespace.
// +patchStrategy=replace
// +optional
Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,2,opt,name=selector"`
Selector *metav1.LabelSelector `json:"selector,omitempty" patchStrategy:"replace" protobuf:"bytes,2,opt,name=selector"`
// An eviction is allowed if at most "maxUnavailable" pods selected by
// "selector" are unavailable after the eviction, i.e. even in absence of
@ -118,7 +122,9 @@ const (
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.5
// +k8s:prerelease-lifecycle-gen:deprecated=1.22
// +k8s:prerelease-lifecycle-gen:deprecated=1.21
// +k8s:prerelease-lifecycle-gen:removed=1.25
// +k8s:prerelease-lifecycle-gen:replacement=policy,v1,PodDisruptionBudget
// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods
type PodDisruptionBudget struct {
@ -136,7 +142,9 @@ type PodDisruptionBudget struct {
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.5
// +k8s:prerelease-lifecycle-gen:deprecated=1.22
// +k8s:prerelease-lifecycle-gen:deprecated=1.21
// +k8s:prerelease-lifecycle-gen:removed=1.25
// +k8s:prerelease-lifecycle-gen:replacement=policy,v1,PodDisruptionBudgetList
// PodDisruptionBudgetList is a collection of PodDisruptionBudgets.
type PodDisruptionBudgetList struct {

View File

@ -116,7 +116,7 @@ func (PodDisruptionBudgetList) SwaggerDoc() map[string]string {
var map_PodDisruptionBudgetSpec = map[string]string{
"": "PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.",
"minAvailable": "An eviction is allowed if at least \"minAvailable\" pods selected by \"selector\" will still be available after the eviction, i.e. even in the absence of the evicted pod. So for example you can prevent all voluntary evictions by specifying \"100%\".",
"selector": "Label query over pods whose evictions are managed by the disruption budget.",
"selector": "Label query over pods whose evictions are managed by the disruption budget. A null selector selects no pods. An empty selector ({}) also selects no pods, which differs from standard behavior of selecting all pods. In policy/v1, an empty selector will select all pods in the namespace.",
"maxUnavailable": "An eviction is allowed if at most \"maxUnavailable\" pods selected by \"selector\" are unavailable after the eviction, i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions by specifying 0. This is a mutually exclusive setting with \"minAvailable\".",
}

View File

@ -20,6 +20,10 @@ limitations under the License.
package v1beta1
import (
schema "k8s.io/apimachinery/pkg/runtime/schema"
)
// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.
// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go.
func (in *Eviction) APILifecycleIntroduced() (major, minor int) {
@ -47,7 +51,13 @@ func (in *PodDisruptionBudget) APILifecycleIntroduced() (major, minor int) {
// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.
// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor.
func (in *PodDisruptionBudget) APILifecycleDeprecated() (major, minor int) {
return 1, 22
return 1, 21
}
// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.
// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=<group>,<version>,<kind>" tags in types.go.
func (in *PodDisruptionBudget) APILifecycleReplacement() schema.GroupVersionKind {
return schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"}
}
// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.
@ -65,7 +75,13 @@ func (in *PodDisruptionBudgetList) APILifecycleIntroduced() (major, minor int) {
// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.
// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor.
func (in *PodDisruptionBudgetList) APILifecycleDeprecated() (major, minor int) {
return 1, 22
return 1, 21
}
// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.
// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=<group>,<version>,<kind>" tags in types.go.
func (in *PodDisruptionBudgetList) APILifecycleReplacement() schema.GroupVersionKind {
return schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "PodDisruptionBudgetList"}
}
// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.

View File

@ -55,6 +55,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -110,6 +111,7 @@ var groups = []runtime.SchemeBuilder{
nodev1.SchemeBuilder,
nodev1alpha1.SchemeBuilder,
nodev1beta1.SchemeBuilder,
policyv1.SchemeBuilder,
policyv1beta1.SchemeBuilder,
rbacv1alpha1.SchemeBuilder,
rbacv1beta1.SchemeBuilder,

View File

@ -0,0 +1,81 @@
{
"kind": "PodDisruptionBudget",
"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"
}
]
},
"spec": {
"minAvailable": 2,
"selector": {
"matchLabels": {
"8---jop9641lg.p-g8c2-k-912e5-c-e63-n-3n/E9.8ThjT9s-j41-0-6p-JFHn7y-74.-0MUORQQ.N2.3": "68._bQw.-dG6c-.6--_x.--0wmZk1_8._3s_-_Bq.m_4"
},
"matchExpressions": [
{
"key": "p503---477-49p---o61---4fy--9---7--9-9s-0-u5lj2--10pq-0-7-9-2-0/fP81.-.9Vdx.TB_M-H_5_.t..bG0",
"operator": "In",
"values": [
"D07.a_.y_y_o0_5qN2_---_M.N_._a6.9bHjdH.-.5_.I8__n"
]
}
]
},
"maxUnavailable": 3
},
"status": {
"observedGeneration": -6582200896939805980,
"disruptedPods": {
"25": "2250-04-18T21:52:38Z"
},
"disruptionsAllowed": -1942073618,
"currentHealthy": -2037845840,
"desiredHealthy": -1965578645,
"expectedPods": -347579237,
"conditions": [
{
"type": "26",
"status": "蓿彭聡A3fƻfʣ繡楙¯ĦE勗E濞",
"observedGeneration": -8886126363972008903,
"lastTransitionTime": "2544-09-25T10:59:09Z",
"reason": "27",
"message": "28"
}
]
}
}

View File

@ -0,0 +1,57 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
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"
spec:
maxUnavailable: 3
minAvailable: 2
selector:
matchExpressions:
- key: p503---477-49p---o61---4fy--9---7--9-9s-0-u5lj2--10pq-0-7-9-2-0/fP81.-.9Vdx.TB_M-H_5_.t..bG0
operator: In
values:
- D07.a_.y_y_o0_5qN2_---_M.N_._a6.9bHjdH.-.5_.I8__n
matchLabels:
8---jop9641lg.p-g8c2-k-912e5-c-e63-n-3n/E9.8ThjT9s-j41-0-6p-JFHn7y-74.-0MUORQQ.N2.3: 68._bQw.-dG6c-.6--_x.--0wmZk1_8._3s_-_Bq.m_4
status:
conditions:
- lastTransitionTime: "2544-09-25T10:59:09Z"
message: "28"
observedGeneration: -8886126363972008903
reason: "27"
status: 蓿彭聡A3fƻfʣ繡楙¯ĦE勗E濞
type: "26"
currentHealthy: -2037845840
desiredHealthy: -1965578645
disruptedPods:
"25": "2250-04-18T21:52:38Z"
disruptionsAllowed: -1942073618
expectedPods: -347579237
observedGeneration: -6582200896939805980

View File

@ -0,0 +1,237 @@
/*
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 (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// PodDisruptionBudgetApplyConfiguration represents an declarative configuration of the PodDisruptionBudget type for use
// with apply.
type PodDisruptionBudgetApplyConfiguration struct {
v1.TypeMetaApplyConfiguration `json:",inline"`
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
Spec *PodDisruptionBudgetSpecApplyConfiguration `json:"spec,omitempty"`
Status *PodDisruptionBudgetStatusApplyConfiguration `json:"status,omitempty"`
}
// PodDisruptionBudget constructs an declarative configuration of the PodDisruptionBudget type for use with
// apply.
func PodDisruptionBudget(name, namespace string) *PodDisruptionBudgetApplyConfiguration {
b := &PodDisruptionBudgetApplyConfiguration{}
b.WithName(name)
b.WithNamespace(namespace)
b.WithKind("PodDisruptionBudget")
b.WithAPIVersion("policy/v1")
return b
}
// 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 *PodDisruptionBudgetApplyConfiguration) WithKind(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithAPIVersion(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithName(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithGenerateName(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithNamespace(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithSelfLink(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithUID(value types.UID) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithResourceVersion(value string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithGeneration(value int64) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithCreationTimestamp(value metav1.Time) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithLabels(entries map[string]string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithAnnotations(entries map[string]string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithFinalizers(values ...string) *PodDisruptionBudgetApplyConfiguration {
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 *PodDisruptionBudgetApplyConfiguration) WithClusterName(value string) *PodDisruptionBudgetApplyConfiguration {
b.ensureObjectMetaApplyConfigurationExists()
b.ClusterName = &value
return b
}
func (b *PodDisruptionBudgetApplyConfiguration) ensureObjectMetaApplyConfigurationExists() {
if b.ObjectMetaApplyConfiguration == nil {
b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{}
}
}
// WithSpec sets the Spec 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 Spec field is set to the value of the last call.
func (b *PodDisruptionBudgetApplyConfiguration) WithSpec(value *PodDisruptionBudgetSpecApplyConfiguration) *PodDisruptionBudgetApplyConfiguration {
b.Spec = value
return b
}
// WithStatus sets the Status 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 Status field is set to the value of the last call.
func (b *PodDisruptionBudgetApplyConfiguration) WithStatus(value *PodDisruptionBudgetStatusApplyConfiguration) *PodDisruptionBudgetApplyConfiguration {
b.Status = value
return b
}

View File

@ -0,0 +1,62 @@
/*
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 (
intstr "k8s.io/apimachinery/pkg/util/intstr"
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// PodDisruptionBudgetSpecApplyConfiguration represents an declarative configuration of the PodDisruptionBudgetSpec type for use
// with apply.
type PodDisruptionBudgetSpecApplyConfiguration struct {
MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty"`
Selector *v1.LabelSelectorApplyConfiguration `json:"selector,omitempty"`
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
}
// PodDisruptionBudgetSpecApplyConfiguration constructs an declarative configuration of the PodDisruptionBudgetSpec type for use with
// apply.
func PodDisruptionBudgetSpec() *PodDisruptionBudgetSpecApplyConfiguration {
return &PodDisruptionBudgetSpecApplyConfiguration{}
}
// WithMinAvailable sets the MinAvailable 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 MinAvailable field is set to the value of the last call.
func (b *PodDisruptionBudgetSpecApplyConfiguration) WithMinAvailable(value intstr.IntOrString) *PodDisruptionBudgetSpecApplyConfiguration {
b.MinAvailable = &value
return b
}
// WithSelector sets the Selector 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 Selector field is set to the value of the last call.
func (b *PodDisruptionBudgetSpecApplyConfiguration) WithSelector(value *v1.LabelSelectorApplyConfiguration) *PodDisruptionBudgetSpecApplyConfiguration {
b.Selector = value
return b
}
// WithMaxUnavailable sets the MaxUnavailable 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 MaxUnavailable field is set to the value of the last call.
func (b *PodDisruptionBudgetSpecApplyConfiguration) WithMaxUnavailable(value intstr.IntOrString) *PodDisruptionBudgetSpecApplyConfiguration {
b.MaxUnavailable = &value
return b
}

View File

@ -0,0 +1,109 @@
/*
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 (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/client-go/applyconfigurations/meta/v1"
)
// PodDisruptionBudgetStatusApplyConfiguration represents an declarative configuration of the PodDisruptionBudgetStatus type for use
// with apply.
type PodDisruptionBudgetStatusApplyConfiguration struct {
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
DisruptedPods map[string]v1.Time `json:"disruptedPods,omitempty"`
DisruptionsAllowed *int32 `json:"disruptionsAllowed,omitempty"`
CurrentHealthy *int32 `json:"currentHealthy,omitempty"`
DesiredHealthy *int32 `json:"desiredHealthy,omitempty"`
ExpectedPods *int32 `json:"expectedPods,omitempty"`
Conditions []metav1.ConditionApplyConfiguration `json:"conditions,omitempty"`
}
// PodDisruptionBudgetStatusApplyConfiguration constructs an declarative configuration of the PodDisruptionBudgetStatus type for use with
// apply.
func PodDisruptionBudgetStatus() *PodDisruptionBudgetStatusApplyConfiguration {
return &PodDisruptionBudgetStatusApplyConfiguration{}
}
// WithObservedGeneration sets the ObservedGeneration 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 ObservedGeneration field is set to the value of the last call.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithObservedGeneration(value int64) *PodDisruptionBudgetStatusApplyConfiguration {
b.ObservedGeneration = &value
return b
}
// WithDisruptedPods puts the entries into the DisruptedPods 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 DisruptedPods field,
// overwriting an existing map entries in DisruptedPods field with the same key.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithDisruptedPods(entries map[string]v1.Time) *PodDisruptionBudgetStatusApplyConfiguration {
if b.DisruptedPods == nil && len(entries) > 0 {
b.DisruptedPods = make(map[string]v1.Time, len(entries))
}
for k, v := range entries {
b.DisruptedPods[k] = v
}
return b
}
// WithDisruptionsAllowed sets the DisruptionsAllowed 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 DisruptionsAllowed field is set to the value of the last call.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithDisruptionsAllowed(value int32) *PodDisruptionBudgetStatusApplyConfiguration {
b.DisruptionsAllowed = &value
return b
}
// WithCurrentHealthy sets the CurrentHealthy 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 CurrentHealthy field is set to the value of the last call.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithCurrentHealthy(value int32) *PodDisruptionBudgetStatusApplyConfiguration {
b.CurrentHealthy = &value
return b
}
// WithDesiredHealthy sets the DesiredHealthy 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 DesiredHealthy field is set to the value of the last call.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithDesiredHealthy(value int32) *PodDisruptionBudgetStatusApplyConfiguration {
b.DesiredHealthy = &value
return b
}
// WithExpectedPods sets the ExpectedPods 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 ExpectedPods field is set to the value of the last call.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithExpectedPods(value int32) *PodDisruptionBudgetStatusApplyConfiguration {
b.ExpectedPods = &value
return b
}
// WithConditions adds the given value to the Conditions 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 Conditions field.
func (b *PodDisruptionBudgetStatusApplyConfiguration) WithConditions(values ...*metav1.ConditionApplyConfiguration) *PodDisruptionBudgetStatusApplyConfiguration {
for i := range values {
if values[i] == nil {
panic("nil value passed to WithConditions")
}
b.Conditions = append(b.Conditions, *values[i])
}
return b
}

View File

@ -48,6 +48,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -90,6 +91,7 @@ import (
applyconfigurationsnodev1 "k8s.io/client-go/applyconfigurations/node/v1"
applyconfigurationsnodev1alpha1 "k8s.io/client-go/applyconfigurations/node/v1alpha1"
applyconfigurationsnodev1beta1 "k8s.io/client-go/applyconfigurations/node/v1beta1"
applyconfigurationspolicyv1 "k8s.io/client-go/applyconfigurations/policy/v1"
applyconfigurationspolicyv1beta1 "k8s.io/client-go/applyconfigurations/policy/v1beta1"
applyconfigurationsrbacv1 "k8s.io/client-go/applyconfigurations/rbac/v1"
applyconfigurationsrbacv1alpha1 "k8s.io/client-go/applyconfigurations/rbac/v1alpha1"
@ -1126,6 +1128,14 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
case nodev1beta1.SchemeGroupVersion.WithKind("Scheduling"):
return &applyconfigurationsnodev1beta1.SchedulingApplyConfiguration{}
// Group=policy, Version=v1
case policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudget"):
return &applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration{}
case policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudgetSpec"):
return &applyconfigurationspolicyv1.PodDisruptionBudgetSpecApplyConfiguration{}
case policyv1.SchemeGroupVersion.WithKind("PodDisruptionBudgetStatus"):
return &applyconfigurationspolicyv1.PodDisruptionBudgetStatusApplyConfiguration{}
// Group=policy, Version=v1beta1
case policyv1beta1.SchemeGroupVersion.WithKind("AllowedCSIDriver"):
return &applyconfigurationspolicyv1beta1.AllowedCSIDriverApplyConfiguration{}

View File

@ -49,6 +49,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -277,6 +278,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
case nodev1beta1.SchemeGroupVersion.WithResource("runtimeclasses"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Node().V1beta1().RuntimeClasses().Informer()}, nil
// Group=policy, Version=v1
case policyv1.SchemeGroupVersion.WithResource("poddisruptionbudgets"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Policy().V1().PodDisruptionBudgets().Informer()}, nil
// Group=policy, Version=v1beta1
case policyv1beta1.SchemeGroupVersion.WithResource("poddisruptionbudgets"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Policy().V1beta1().PodDisruptionBudgets().Informer()}, nil

View File

@ -20,11 +20,14 @@ package policy
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
v1 "k8s.io/client-go/informers/policy/v1"
v1beta1 "k8s.io/client-go/informers/policy/v1beta1"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1 provides access to shared informers for resources in V1.
V1() v1.Interface
// V1beta1 provides access to shared informers for resources in V1beta1.
V1beta1() v1beta1.Interface
}
@ -40,6 +43,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1 returns a new v1.Interface.
func (g *group) V1() v1.Interface {
return v1.New(g.factory, g.namespace, g.tweakListOptions)
}
// V1beta1 returns a new v1beta1.Interface.
func (g *group) V1beta1() v1beta1.Interface {
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)

View File

@ -0,0 +1,45 @@
/*
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 informer-gen. DO NOT EDIT.
package v1
import (
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// PodDisruptionBudgets returns a PodDisruptionBudgetInformer.
PodDisruptionBudgets() PodDisruptionBudgetInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// PodDisruptionBudgets returns a PodDisruptionBudgetInformer.
func (v *version) PodDisruptionBudgets() PodDisruptionBudgetInformer {
return &podDisruptionBudgetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@ -0,0 +1,90 @@
/*
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 informer-gen. DO NOT EDIT.
package v1
import (
"context"
time "time"
policyv1 "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
kubernetes "k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/listers/policy/v1"
cache "k8s.io/client-go/tools/cache"
)
// PodDisruptionBudgetInformer provides access to a shared informer and lister for
// PodDisruptionBudgets.
type PodDisruptionBudgetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.PodDisruptionBudgetLister
}
type podDisruptionBudgetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewPodDisruptionBudgetInformer constructs a new informer for PodDisruptionBudget type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPodDisruptionBudgetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredPodDisruptionBudgetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredPodDisruptionBudgetInformer constructs a new informer for PodDisruptionBudget type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPodDisruptionBudgetInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.PolicyV1().PodDisruptionBudgets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.PolicyV1().PodDisruptionBudgets(namespace).Watch(context.TODO(), options)
},
},
&policyv1.PodDisruptionBudget{},
resyncPeriod,
indexers,
)
}
func (f *podDisruptionBudgetInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredPodDisruptionBudgetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *podDisruptionBudgetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&policyv1.PodDisruptionBudget{}, f.defaultInformer)
}
func (f *podDisruptionBudgetInformer) Lister() v1.PodDisruptionBudgetLister {
return v1.NewPodDisruptionBudgetLister(f.Informer().GetIndexer())
}

View File

@ -54,6 +54,7 @@ import (
nodev1 "k8s.io/client-go/kubernetes/typed/node/v1"
nodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1"
nodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1"
policyv1 "k8s.io/client-go/kubernetes/typed/policy/v1"
policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
rbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
rbacv1alpha1 "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1"
@ -102,6 +103,7 @@ type Interface interface {
NodeV1() nodev1.NodeV1Interface
NodeV1alpha1() nodev1alpha1.NodeV1alpha1Interface
NodeV1beta1() nodev1beta1.NodeV1beta1Interface
PolicyV1() policyv1.PolicyV1Interface
PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface
RbacV1() rbacv1.RbacV1Interface
RbacV1beta1() rbacv1beta1.RbacV1beta1Interface
@ -150,6 +152,7 @@ type Clientset struct {
nodeV1 *nodev1.NodeV1Client
nodeV1alpha1 *nodev1alpha1.NodeV1alpha1Client
nodeV1beta1 *nodev1beta1.NodeV1beta1Client
policyV1 *policyv1.PolicyV1Client
policyV1beta1 *policyv1beta1.PolicyV1beta1Client
rbacV1 *rbacv1.RbacV1Client
rbacV1beta1 *rbacv1beta1.RbacV1beta1Client
@ -322,6 +325,11 @@ func (c *Clientset) NodeV1beta1() nodev1beta1.NodeV1beta1Interface {
return c.nodeV1beta1
}
// PolicyV1 retrieves the PolicyV1Client
func (c *Clientset) PolicyV1() policyv1.PolicyV1Interface {
return c.policyV1
}
// PolicyV1beta1 retrieves the PolicyV1beta1Client
func (c *Clientset) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface {
return c.policyV1beta1
@ -521,6 +529,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
if err != nil {
return nil, err
}
cs.policyV1, err = policyv1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
}
cs.policyV1beta1, err = policyv1beta1.NewForConfig(&configShallowCopy)
if err != nil {
return nil, err
@ -605,6 +617,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
cs.nodeV1 = nodev1.NewForConfigOrDie(c)
cs.nodeV1alpha1 = nodev1alpha1.NewForConfigOrDie(c)
cs.nodeV1beta1 = nodev1beta1.NewForConfigOrDie(c)
cs.policyV1 = policyv1.NewForConfigOrDie(c)
cs.policyV1beta1 = policyv1beta1.NewForConfigOrDie(c)
cs.rbacV1 = rbacv1.NewForConfigOrDie(c)
cs.rbacV1beta1 = rbacv1beta1.NewForConfigOrDie(c)
@ -655,6 +668,7 @@ func New(c rest.Interface) *Clientset {
cs.nodeV1 = nodev1.New(c)
cs.nodeV1alpha1 = nodev1alpha1.New(c)
cs.nodeV1beta1 = nodev1beta1.New(c)
cs.policyV1 = policyv1.New(c)
cs.policyV1beta1 = policyv1beta1.New(c)
cs.rbacV1 = rbacv1.New(c)
cs.rbacV1beta1 = rbacv1beta1.New(c)

View File

@ -88,6 +88,8 @@ import (
fakenodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake"
nodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1"
fakenodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1/fake"
policyv1 "k8s.io/client-go/kubernetes/typed/policy/v1"
fakepolicyv1 "k8s.io/client-go/kubernetes/typed/policy/v1/fake"
policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
fakepolicyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake"
rbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
@ -318,6 +320,11 @@ func (c *Clientset) NodeV1beta1() nodev1beta1.NodeV1beta1Interface {
return &fakenodev1beta1.FakeNodeV1beta1{Fake: &c.Fake}
}
// PolicyV1 retrieves the PolicyV1Client
func (c *Clientset) PolicyV1() policyv1.PolicyV1Interface {
return &fakepolicyv1.FakePolicyV1{Fake: &c.Fake}
}
// PolicyV1beta1 retrieves the PolicyV1beta1Client
func (c *Clientset) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface {
return &fakepolicyv1beta1.FakePolicyV1beta1{Fake: &c.Fake}

View File

@ -51,6 +51,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -104,6 +105,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{
nodev1.AddToScheme,
nodev1alpha1.AddToScheme,
nodev1beta1.AddToScheme,
policyv1.AddToScheme,
policyv1beta1.AddToScheme,
rbacv1.AddToScheme,
rbacv1beta1.AddToScheme,

View File

@ -51,6 +51,7 @@ import (
nodev1 "k8s.io/api/node/v1"
nodev1alpha1 "k8s.io/api/node/v1alpha1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -104,6 +105,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{
nodev1.AddToScheme,
nodev1alpha1.AddToScheme,
nodev1beta1.AddToScheme,
policyv1.AddToScheme,
policyv1beta1.AddToScheme,
rbacv1.AddToScheme,
rbacv1beta1.AddToScheme,

View File

@ -0,0 +1,20 @@
/*
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.
// This package has the automatically generated typed clients.
package v1

View File

@ -0,0 +1,20 @@
/*
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 has the automatically generated clients.
package fake

View File

@ -0,0 +1,190 @@
/*
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
import (
"context"
json "encoding/json"
"fmt"
policyv1 "k8s.io/api/policy/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
applyconfigurationspolicyv1 "k8s.io/client-go/applyconfigurations/policy/v1"
testing "k8s.io/client-go/testing"
)
// FakePodDisruptionBudgets implements PodDisruptionBudgetInterface
type FakePodDisruptionBudgets struct {
Fake *FakePolicyV1
ns string
}
var poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1", Resource: "poddisruptionbudgets"}
var poddisruptionbudgetsKind = schema.GroupVersionKind{Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"}
// Get takes name of the podDisruptionBudget, and returns the corresponding podDisruptionBudget object, and an error if there is any.
func (c *FakePodDisruptionBudgets) Get(ctx context.Context, name string, options v1.GetOptions) (result *policyv1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(poddisruptionbudgetsResource, c.ns, name), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// List takes label and field selectors, and returns the list of PodDisruptionBudgets that match those selectors.
func (c *FakePodDisruptionBudgets) List(ctx context.Context, opts v1.ListOptions) (result *policyv1.PodDisruptionBudgetList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(poddisruptionbudgetsResource, poddisruptionbudgetsKind, c.ns, opts), &policyv1.PodDisruptionBudgetList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &policyv1.PodDisruptionBudgetList{ListMeta: obj.(*policyv1.PodDisruptionBudgetList).ListMeta}
for _, item := range obj.(*policyv1.PodDisruptionBudgetList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested podDisruptionBudgets.
func (c *FakePodDisruptionBudgets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(poddisruptionbudgetsResource, c.ns, opts))
}
// Create takes the representation of a podDisruptionBudget and creates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *FakePodDisruptionBudgets) Create(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.CreateOptions) (result *policyv1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// Update takes the representation of a podDisruptionBudget and updates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *FakePodDisruptionBudgets) Update(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.UpdateOptions) (result *policyv1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakePodDisruptionBudgets) UpdateStatus(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts v1.UpdateOptions) (*policyv1.PodDisruptionBudget, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(poddisruptionbudgetsResource, "status", c.ns, podDisruptionBudget), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// Delete takes name of the podDisruptionBudget and deletes it. Returns an error if one occurs.
func (c *FakePodDisruptionBudgets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(poddisruptionbudgetsResource, c.ns, name), &policyv1.PodDisruptionBudget{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakePodDisruptionBudgets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(poddisruptionbudgetsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &policyv1.PodDisruptionBudgetList{})
return err
}
// Patch applies the patch and returns the patched podDisruptionBudget.
func (c *FakePodDisruptionBudgets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *policyv1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, name, pt, data, subresources...), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// Apply takes the given apply declarative configuration, applies it and returns the applied podDisruptionBudget.
func (c *FakePodDisruptionBudgets) Apply(ctx context.Context, podDisruptionBudget *applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *policyv1.PodDisruptionBudget, err error) {
if podDisruptionBudget == nil {
return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil")
}
data, err := json.Marshal(podDisruptionBudget)
if err != nil {
return nil, err
}
name := podDisruptionBudget.Name
if name == nil {
return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply")
}
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}
// ApplyStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
func (c *FakePodDisruptionBudgets) ApplyStatus(ctx context.Context, podDisruptionBudget *applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration, opts v1.ApplyOptions) (result *policyv1.PodDisruptionBudget, err error) {
if podDisruptionBudget == nil {
return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil")
}
data, err := json.Marshal(podDisruptionBudget)
if err != nil {
return nil, err
}
name := podDisruptionBudget.Name
if name == nil {
return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply")
}
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, *name, types.ApplyPatchType, data, "status"), &policyv1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*policyv1.PodDisruptionBudget), err
}

View File

@ -0,0 +1,40 @@
/*
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
import (
v1 "k8s.io/client-go/kubernetes/typed/policy/v1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakePolicyV1 struct {
*testing.Fake
}
func (c *FakePolicyV1) PodDisruptionBudgets(namespace string) v1.PodDisruptionBudgetInterface {
return &FakePodDisruptionBudgets{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakePolicyV1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@ -0,0 +1,21 @@
/*
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
type PodDisruptionBudgetExpansion interface{}

View File

@ -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 client-gen. DO NOT EDIT.
package v1
import (
"context"
json "encoding/json"
"fmt"
"time"
v1 "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
policyv1 "k8s.io/client-go/applyconfigurations/policy/v1"
scheme "k8s.io/client-go/kubernetes/scheme"
rest "k8s.io/client-go/rest"
)
// PodDisruptionBudgetsGetter has a method to return a PodDisruptionBudgetInterface.
// A group's client should implement this interface.
type PodDisruptionBudgetsGetter interface {
PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface
}
// PodDisruptionBudgetInterface has methods to work with PodDisruptionBudget resources.
type PodDisruptionBudgetInterface interface {
Create(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.CreateOptions) (*v1.PodDisruptionBudget, error)
Update(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.UpdateOptions) (*v1.PodDisruptionBudget, error)
UpdateStatus(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.UpdateOptions) (*v1.PodDisruptionBudget, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.PodDisruptionBudget, error)
List(ctx context.Context, opts metav1.ListOptions) (*v1.PodDisruptionBudgetList, error)
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.PodDisruptionBudget, err error)
Apply(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudgetApplyConfiguration, opts metav1.ApplyOptions) (result *v1.PodDisruptionBudget, err error)
ApplyStatus(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudgetApplyConfiguration, opts metav1.ApplyOptions) (result *v1.PodDisruptionBudget, err error)
PodDisruptionBudgetExpansion
}
// podDisruptionBudgets implements PodDisruptionBudgetInterface
type podDisruptionBudgets struct {
client rest.Interface
ns string
}
// newPodDisruptionBudgets returns a PodDisruptionBudgets
func newPodDisruptionBudgets(c *PolicyV1Client, namespace string) *podDisruptionBudgets {
return &podDisruptionBudgets{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the podDisruptionBudget, and returns the corresponding podDisruptionBudget object, and an error if there is any.
func (c *podDisruptionBudgets) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.PodDisruptionBudget, err error) {
result = &v1.PodDisruptionBudget{}
err = c.client.Get().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of PodDisruptionBudgets that match those selectors.
func (c *podDisruptionBudgets) List(ctx context.Context, opts metav1.ListOptions) (result *v1.PodDisruptionBudgetList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.PodDisruptionBudgetList{}
err = c.client.Get().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested podDisruptionBudgets.
func (c *podDisruptionBudgets) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a podDisruptionBudget and creates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *podDisruptionBudgets) Create(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.CreateOptions) (result *v1.PodDisruptionBudget, err error) {
result = &v1.PodDisruptionBudget{}
err = c.client.Post().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&opts, scheme.ParameterCodec).
Body(podDisruptionBudget).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a podDisruptionBudget and updates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *podDisruptionBudgets) Update(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.UpdateOptions) (result *v1.PodDisruptionBudget, err error) {
result = &v1.PodDisruptionBudget{}
err = c.client.Put().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(podDisruptionBudget.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(podDisruptionBudget).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *podDisruptionBudgets) UpdateStatus(ctx context.Context, podDisruptionBudget *v1.PodDisruptionBudget, opts metav1.UpdateOptions) (result *v1.PodDisruptionBudget, err error) {
result = &v1.PodDisruptionBudget{}
err = c.client.Put().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(podDisruptionBudget.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(podDisruptionBudget).
Do(ctx).
Into(result)
return
}
// Delete takes name of the podDisruptionBudget and deletes it. Returns an error if one occurs.
func (c *podDisruptionBudgets) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *podDisruptionBudgets) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched podDisruptionBudget.
func (c *podDisruptionBudgets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.PodDisruptionBudget, err error) {
result = &v1.PodDisruptionBudget{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
// Apply takes the given apply declarative configuration, applies it and returns the applied podDisruptionBudget.
func (c *podDisruptionBudgets) Apply(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudgetApplyConfiguration, opts metav1.ApplyOptions) (result *v1.PodDisruptionBudget, err error) {
if podDisruptionBudget == nil {
return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil")
}
patchOpts := opts.ToPatchOptions()
data, err := json.Marshal(podDisruptionBudget)
if err != nil {
return nil, err
}
name := podDisruptionBudget.Name
if name == nil {
return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply")
}
result = &v1.PodDisruptionBudget{}
err = c.client.Patch(types.ApplyPatchType).
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(*name).
VersionedParams(&patchOpts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
// ApplyStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
func (c *podDisruptionBudgets) ApplyStatus(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudgetApplyConfiguration, opts metav1.ApplyOptions) (result *v1.PodDisruptionBudget, err error) {
if podDisruptionBudget == nil {
return nil, fmt.Errorf("podDisruptionBudget provided to Apply must not be nil")
}
patchOpts := opts.ToPatchOptions()
data, err := json.Marshal(podDisruptionBudget)
if err != nil {
return nil, err
}
name := podDisruptionBudget.Name
if name == nil {
return nil, fmt.Errorf("podDisruptionBudget.Name must be provided to Apply")
}
result = &v1.PodDisruptionBudget{}
err = c.client.Patch(types.ApplyPatchType).
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(*name).
SubResource("status").
VersionedParams(&patchOpts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -0,0 +1,89 @@
/*
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 (
v1 "k8s.io/api/policy/v1"
"k8s.io/client-go/kubernetes/scheme"
rest "k8s.io/client-go/rest"
)
type PolicyV1Interface interface {
RESTClient() rest.Interface
PodDisruptionBudgetsGetter
}
// PolicyV1Client is used to interact with features provided by the policy group.
type PolicyV1Client struct {
restClient rest.Interface
}
func (c *PolicyV1Client) PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface {
return newPodDisruptionBudgets(c, namespace)
}
// NewForConfig creates a new PolicyV1Client for the given config.
func NewForConfig(c *rest.Config) (*PolicyV1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &PolicyV1Client{client}, nil
}
// NewForConfigOrDie creates a new PolicyV1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *PolicyV1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new PolicyV1Client for the given RESTClient.
func New(c rest.Interface) *PolicyV1Client {
return &PolicyV1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *PolicyV1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

View File

@ -0,0 +1,19 @@
/*
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

View File

@ -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"
)
// PodDisruptionBudgetLister helps list PodDisruptionBudgets.
// All objects returned here must be treated as read-only.
type PodDisruptionBudgetLister interface {
// List lists all PodDisruptionBudgets in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1.PodDisruptionBudget, err error)
// PodDisruptionBudgets returns an object that can list and get PodDisruptionBudgets.
PodDisruptionBudgets(namespace string) PodDisruptionBudgetNamespaceLister
PodDisruptionBudgetListerExpansion
}
// podDisruptionBudgetLister implements the PodDisruptionBudgetLister interface.
type podDisruptionBudgetLister struct {
indexer cache.Indexer
}
// NewPodDisruptionBudgetLister returns a new PodDisruptionBudgetLister.
func NewPodDisruptionBudgetLister(indexer cache.Indexer) PodDisruptionBudgetLister {
return &podDisruptionBudgetLister{indexer: indexer}
}
// List lists all PodDisruptionBudgets in the indexer.
func (s *podDisruptionBudgetLister) List(selector labels.Selector) (ret []*v1.PodDisruptionBudget, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.PodDisruptionBudget))
})
return ret, err
}
// PodDisruptionBudgets returns an object that can list and get PodDisruptionBudgets.
func (s *podDisruptionBudgetLister) PodDisruptionBudgets(namespace string) PodDisruptionBudgetNamespaceLister {
return podDisruptionBudgetNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// PodDisruptionBudgetNamespaceLister helps list and get PodDisruptionBudgets.
// All objects returned here must be treated as read-only.
type PodDisruptionBudgetNamespaceLister interface {
// List lists all PodDisruptionBudgets in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1.PodDisruptionBudget, err error)
// Get retrieves the PodDisruptionBudget from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1.PodDisruptionBudget, error)
PodDisruptionBudgetNamespaceListerExpansion
}
// podDisruptionBudgetNamespaceLister implements the PodDisruptionBudgetNamespaceLister
// interface.
type podDisruptionBudgetNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all PodDisruptionBudgets in the indexer for a given namespace.
func (s podDisruptionBudgetNamespaceLister) List(selector labels.Selector) (ret []*v1.PodDisruptionBudget, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.PodDisruptionBudget))
})
return ret, err
}
// Get retrieves the PodDisruptionBudget from the indexer for a given namespace and name.
func (s podDisruptionBudgetNamespaceLister) Get(name string) (*v1.PodDisruptionBudget, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1.Resource("poddisruptionbudget"), name)
}
return obj.(*v1.PodDisruptionBudget), nil
}

View File

@ -0,0 +1,69 @@
/*
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 (
"fmt"
"k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/klog/v2"
)
// PodDisruptionBudgetListerExpansion allows custom methods to be added to
// PodDisruptionBudgetLister.
type PodDisruptionBudgetListerExpansion interface {
GetPodPodDisruptionBudgets(pod *v1.Pod) ([]*policy.PodDisruptionBudget, error)
}
// PodDisruptionBudgetNamespaceListerExpansion allows custom methods to be added to
// PodDisruptionBudgetNamespaceLister.
type PodDisruptionBudgetNamespaceListerExpansion interface{}
// GetPodPodDisruptionBudgets returns a list of PodDisruptionBudgets matching a pod.
func (s *podDisruptionBudgetLister) GetPodPodDisruptionBudgets(pod *v1.Pod) ([]*policy.PodDisruptionBudget, error) {
var selector labels.Selector
list, err := s.PodDisruptionBudgets(pod.Namespace).List(labels.Everything())
if err != nil {
return nil, err
}
var pdbList []*policy.PodDisruptionBudget
for i := range list {
pdb := list[i]
selector, err = metav1.LabelSelectorAsSelector(pdb.Spec.Selector)
if err != nil {
klog.Warningf("invalid selector: %v", err)
continue
}
// Unlike the v1beta version, here we let an empty selector match everything.
if !selector.Matches(labels.Set(pod.Labels)) {
continue
}
pdbList = append(pdbList, pdb)
}
if len(pdbList) == 0 {
return nil, fmt.Errorf("could not find PodDisruptionBudget for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels)
}
return pdbList, nil
}

View File

@ -40,10 +40,6 @@ type PodDisruptionBudgetNamespaceListerExpansion interface{}
func (s *podDisruptionBudgetLister) GetPodPodDisruptionBudgets(pod *v1.Pod) ([]*policy.PodDisruptionBudget, error) {
var selector labels.Selector
if len(pod.Labels) == 0 {
return nil, fmt.Errorf("no PodDisruptionBudgets found for pod %v because it has no labels", pod.Name)
}
list, err := s.PodDisruptionBudgets(pod.Namespace).List(labels.Everything())
if err != nil {
return nil, err

View File

@ -17,7 +17,7 @@ limitations under the License.
package poddisruptionbudget
import (
policy "k8s.io/api/policy/v1beta1"
policy "k8s.io/api/policy/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

View File

@ -38,6 +38,7 @@ import (
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
imagepolicyv1alpha1 "k8s.io/api/imagepolicy/v1alpha1"
networkingv1 "k8s.io/api/networking/v1"
policyv1 "k8s.io/api/policy/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -74,7 +75,7 @@ func init() {
utilruntime.Must(Scheme.SetVersionPriority(extensionsv1beta1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(imagepolicyv1alpha1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(networkingv1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(policyv1beta1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(policyv1beta1.SchemeGroupVersion, policyv1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(rbacv1.SchemeGroupVersion, rbacv1beta1.SchemeGroupVersion, rbacv1alpha1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(schedulingv1alpha1.SchemeGroupVersion))
utilruntime.Must(Scheme.SetVersionPriority(storagev1.SchemeGroupVersion, storagev1beta1.SchemeGroupVersion))

View File

@ -27,6 +27,7 @@ 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"
@ -103,7 +104,7 @@ var _ = SIGDescribe("DisruptionController", func() {
// Since disruptionAllowed starts out 0, if we see it ever become positive,
// that means the controller is working.
err := wait.PollImmediate(framework.Poll, timeout, func() (bool, error) {
pdb, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), defaultName, metav1.GetOptions{})
pdb, err := cs.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), defaultName, metav1.GetOptions{})
if err != nil {
return false, err
}
@ -121,17 +122,17 @@ var _ = SIGDescribe("DisruptionController", func() {
createPodsOrDie(cs, ns, 1)
waitForPodsOrDie(cs, ns, 1)
pod, _ := locateRunningPod(cs, ns)
updatePDBOrDie(cs, ns, defaultName, func(old *policyv1beta1.PodDisruptionBudget) *policyv1beta1.PodDisruptionBudget {
updatePDBOrDie(cs, ns, defaultName, func(old *policyv1.PodDisruptionBudget) *policyv1.PodDisruptionBudget {
old.Status.DisruptedPods = make(map[string]metav1.Time)
old.Status.DisruptedPods[pod.Name] = metav1.NewTime(time.Now())
return old
}, cs.PolicyV1beta1().PodDisruptionBudgets(ns).UpdateStatus)
}, cs.PolicyV1().PodDisruptionBudgets(ns).UpdateStatus)
// fetch again to make sure the update from API was effective
updated := getPDBStatusOrDie(dc, ns, defaultName)
framework.ExpectHaveKey(updated.Status.DisruptedPods, pod.Name, "Expecting the DisruptedPods have %s", pod.Name)
ginkgo.By("Patching PodDisruptionBudget status")
patched := patchPDBOrDie(cs, dc, ns, defaultName, func(old *policyv1beta1.PodDisruptionBudget) (bytes []byte, err error) {
patched := patchPDBOrDie(cs, dc, ns, defaultName, func(old *policyv1.PodDisruptionBudget) (bytes []byte, err error) {
oldBytes, err := json.Marshal(old)
framework.ExpectNoError(err, "failed to marshal JSON for old data")
old.Status.DisruptedPods = make(map[string]metav1.Time)
@ -290,11 +291,11 @@ var _ = SIGDescribe("DisruptionController", func() {
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")
updatePDBOrDie(cs, ns, defaultName, func(pdb *policyv1beta1.PodDisruptionBudget) *policyv1beta1.PodDisruptionBudget {
updatePDBOrDie(cs, ns, defaultName, func(pdb *policyv1.PodDisruptionBudget) *policyv1.PodDisruptionBudget {
newMinAvailable := intstr.FromInt(2)
pdb.Spec.MinAvailable = &newMinAvailable
return pdb
}, cs.PolicyV1beta1().PodDisruptionBudgets(ns).Update)
}, cs.PolicyV1().PodDisruptionBudgets(ns).Update)
ginkgo.By("Trying to evict the same pod we tried earlier which should now be evictable")
waitForPodsOrDie(cs, ns, 3)
@ -303,7 +304,7 @@ var _ = SIGDescribe("DisruptionController", func() {
framework.ExpectNoError(err) // the eviction is now allowed
ginkgo.By("Patching the pdb to disallow a pod to be evicted")
patchPDBOrDie(cs, dc, ns, defaultName, func(old *policyv1beta1.PodDisruptionBudget) (bytes []byte, err error) {
patchPDBOrDie(cs, dc, ns, defaultName, func(old *policyv1.PodDisruptionBudget) (bytes []byte, err error) {
oldData, err := json.Marshal(old)
framework.ExpectNoError(err, "failed to marshal JSON for old data")
old.Spec.MinAvailable = nil
@ -338,45 +339,45 @@ var _ = SIGDescribe("DisruptionController", func() {
})
func createPDBMinAvailableOrDie(cs kubernetes.Interface, ns string, name string, minAvailable intstr.IntOrString, labels map[string]string) {
pdb := policyv1beta1.PodDisruptionBudget{
pdb := policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
Labels: labels,
},
Spec: policyv1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
MinAvailable: &minAvailable,
},
}
_, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Create(context.TODO(), &pdb, metav1.CreateOptions{})
_, err := cs.PolicyV1().PodDisruptionBudgets(ns).Create(context.TODO(), &pdb, metav1.CreateOptions{})
framework.ExpectNoError(err, "Waiting for the pdb to be created with minAvailable %d in namespace %s", minAvailable.IntVal, ns)
waitForPdbToBeProcessed(cs, ns, name)
}
func createPDBMaxUnavailableOrDie(cs kubernetes.Interface, ns string, name string, maxUnavailable intstr.IntOrString) {
pdb := policyv1beta1.PodDisruptionBudget{
pdb := policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
},
Spec: policyv1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
MaxUnavailable: &maxUnavailable,
},
}
_, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Create(context.TODO(), &pdb, metav1.CreateOptions{})
_, err := cs.PolicyV1().PodDisruptionBudgets(ns).Create(context.TODO(), &pdb, metav1.CreateOptions{})
framework.ExpectNoError(err, "Waiting for the pdb to be created with maxUnavailable %d in namespace %s", maxUnavailable.IntVal, ns)
waitForPdbToBeProcessed(cs, ns, name)
}
type updateFunc func(pdb *policyv1beta1.PodDisruptionBudget) *policyv1beta1.PodDisruptionBudget
type updateRestAPI func(ctx context.Context, podDisruptionBudget *policyv1beta1.PodDisruptionBudget, opts metav1.UpdateOptions) (*policyv1beta1.PodDisruptionBudget, error)
type patchFunc func(pdb *policyv1beta1.PodDisruptionBudget) ([]byte, error)
type updateFunc func(pdb *policyv1.PodDisruptionBudget) *policyv1.PodDisruptionBudget
type updateRestAPI func(ctx context.Context, podDisruptionBudget *policyv1.PodDisruptionBudget, opts metav1.UpdateOptions) (*policyv1.PodDisruptionBudget, error)
type patchFunc func(pdb *policyv1.PodDisruptionBudget) ([]byte, error)
func updatePDBOrDie(cs kubernetes.Interface, ns string, name string, f updateFunc, api updateRestAPI) (updated *policyv1beta1.PodDisruptionBudget) {
func updatePDBOrDie(cs kubernetes.Interface, ns string, name string, f updateFunc, api updateRestAPI) (updated *policyv1.PodDisruptionBudget) {
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
old, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
old, err := cs.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return err
}
@ -392,12 +393,12 @@ func updatePDBOrDie(cs kubernetes.Interface, ns string, name string, f updateFun
return updated
}
func patchPDBOrDie(cs kubernetes.Interface, dc dynamic.Interface, ns string, name string, f patchFunc, subresources ...string) (updated *policyv1beta1.PodDisruptionBudget) {
func patchPDBOrDie(cs kubernetes.Interface, dc dynamic.Interface, ns string, name string, f patchFunc, subresources ...string) (updated *policyv1.PodDisruptionBudget) {
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
old := getPDBStatusOrDie(dc, ns, name)
patchBytes, err := f(old)
framework.ExpectNoError(err)
if updated, err = cs.PolicyV1beta1().PodDisruptionBudgets(ns).Patch(context.TODO(), old.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, subresources...); err != nil {
if updated, err = cs.PolicyV1().PodDisruptionBudgets(ns).Patch(context.TODO(), old.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}, subresources...); err != nil {
return err
}
framework.ExpectNoError(err)
@ -410,13 +411,13 @@ func patchPDBOrDie(cs kubernetes.Interface, dc dynamic.Interface, ns string, nam
}
func deletePDBOrDie(cs kubernetes.Interface, ns string, name string) {
err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
err := cs.PolicyV1().PodDisruptionBudgets(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
framework.ExpectNoError(err, "Deleting pdb in namespace %s", ns)
waitForPdbToBeDeleted(cs, ns, name)
}
func listPDBs(cs kubernetes.Interface, ns string, labelSelector string, count int, expectedPDBNames []string) {
pdbList, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector})
pdbList, err := cs.PolicyV1().PodDisruptionBudgets(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector})
framework.ExpectNoError(err, "Listing PDB set in namespace %s", ns)
framework.ExpectEqual(len(pdbList.Items), count, "Expecting %d PDBs returned in namespace %s", count, ns)
@ -429,7 +430,7 @@ func listPDBs(cs kubernetes.Interface, ns string, labelSelector string, count in
func deletePDBCollection(cs kubernetes.Interface, ns string) {
ginkgo.By("deleting a collection of PDBs")
err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
err := cs.PolicyV1().PodDisruptionBudgets(ns).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
framework.ExpectNoError(err, "Deleting PDB set in namespace %s", ns)
waitForPDBCollectionToBeDeleted(cs, ns)
@ -438,7 +439,7 @@ func deletePDBCollection(cs kubernetes.Interface, ns string) {
func waitForPDBCollectionToBeDeleted(cs kubernetes.Interface, ns string) {
ginkgo.By("Waiting for the PDB collection to be deleted")
err := wait.PollImmediate(framework.Poll, schedulingTimeout, func() (bool, error) {
pdbList, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).List(context.TODO(), metav1.ListOptions{})
pdbList, err := cs.PolicyV1().PodDisruptionBudgets(ns).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return false, err
}
@ -564,7 +565,7 @@ func locateRunningPod(cs kubernetes.Interface, ns string) (pod *v1.Pod, err erro
func waitForPdbToBeProcessed(cs kubernetes.Interface, ns string, name string) {
ginkgo.By("Waiting for the pdb to be processed")
err := wait.PollImmediate(framework.Poll, schedulingTimeout, func() (bool, error) {
pdb, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
pdb, err := cs.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, err
}
@ -579,7 +580,7 @@ func waitForPdbToBeProcessed(cs kubernetes.Interface, ns string, name string) {
func waitForPdbToBeDeleted(cs kubernetes.Interface, ns string, name string) {
ginkgo.By("Waiting for the pdb to be deleted")
err := wait.PollImmediate(framework.Poll, schedulingTimeout, func() (bool, error) {
_, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
_, err := cs.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return true, nil // done
}
@ -594,7 +595,7 @@ func waitForPdbToBeDeleted(cs kubernetes.Interface, ns string, name string) {
func waitForPdbToObserveHealthyPods(cs kubernetes.Interface, ns string, healthyCount int32) {
ginkgo.By("Waiting for the pdb to observed all healthy pods")
err := wait.PollImmediate(framework.Poll, wait.ForeverTestTimeout, func() (bool, error) {
pdb, err := cs.PolicyV1beta1().PodDisruptionBudgets(ns).Get(context.TODO(), "foo", metav1.GetOptions{})
pdb, err := cs.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), "foo", metav1.GetOptions{})
if err != nil {
return false, err
}
@ -606,8 +607,8 @@ func waitForPdbToObserveHealthyPods(cs kubernetes.Interface, ns string, healthyC
framework.ExpectNoError(err, "Waiting for the pdb in namespace %s to observed %d healthy pods", ns, healthyCount)
}
func getPDBStatusOrDie(dc dynamic.Interface, ns string, name string) *policyv1beta1.PodDisruptionBudget {
pdbStatusResource := policyv1beta1.SchemeGroupVersion.WithResource("poddisruptionbudgets")
func getPDBStatusOrDie(dc dynamic.Interface, ns string, name string) *policyv1.PodDisruptionBudget {
pdbStatusResource := policyv1.SchemeGroupVersion.WithResource("poddisruptionbudgets")
unstruct, err := dc.Resource(pdbStatusResource).Namespace(ns).Get(context.TODO(), name, metav1.GetOptions{}, "status")
framework.ExpectNoError(err)
pdb, err := unstructuredToPDB(unstruct)
@ -615,12 +616,12 @@ func getPDBStatusOrDie(dc dynamic.Interface, ns string, name string) *policyv1be
return pdb
}
func unstructuredToPDB(obj *unstructured.Unstructured) (*policyv1beta1.PodDisruptionBudget, error) {
func unstructuredToPDB(obj *unstructured.Unstructured) (*policyv1.PodDisruptionBudget, error) {
json, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil {
return nil, err
}
pdb := &policyv1beta1.PodDisruptionBudget{}
pdb := &policyv1.PodDisruptionBudget{}
err = runtime.DecodeInto(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), json, pdb)
pdb.Kind = ""
pdb.APIVersion = ""

View File

@ -30,7 +30,7 @@ import (
"time"
v1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
policyv1 "k8s.io/api/policy/v1"
schedulingv1 "k8s.io/api/scheduling/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -1028,20 +1028,20 @@ func runDrainTest(f *framework.Framework, migSizes map[string]int, namespace str
ginkgo.By("Create a PodDisruptionBudget")
minAvailable := intstr.FromInt(numPods - pdbSize)
pdb := &policyv1beta1.PodDisruptionBudget{
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: "test_pdb",
Namespace: namespace,
},
Spec: policyv1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: labelMap},
MinAvailable: &minAvailable,
},
}
_, err = f.ClientSet.PolicyV1beta1().PodDisruptionBudgets(namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
_, err = f.ClientSet.PolicyV1().PodDisruptionBudgets(namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
defer func() {
f.ClientSet.PolicyV1beta1().PodDisruptionBudgets(namespace).Delete(context.TODO(), pdb.Name, metav1.DeleteOptions{})
f.ClientSet.PolicyV1().PodDisruptionBudgets(namespace).Delete(context.TODO(), pdb.Name, metav1.DeleteOptions{})
}()
framework.ExpectNoError(err)
@ -1881,7 +1881,7 @@ func addKubeSystemPdbs(f *framework.Framework) (func(), error) {
var finalErr error
for _, newPdbName := range newPdbs {
ginkgo.By(fmt.Sprintf("Delete PodDisruptionBudget %v", newPdbName))
err := f.ClientSet.PolicyV1beta1().PodDisruptionBudgets("kube-system").Delete(context.TODO(), newPdbName, metav1.DeleteOptions{})
err := f.ClientSet.PolicyV1().PodDisruptionBudgets("kube-system").Delete(context.TODO(), newPdbName, metav1.DeleteOptions{})
if err != nil {
// log error, but attempt to remove other pdbs
klog.Errorf("Failed to delete PodDisruptionBudget %v, err: %v", newPdbName, err)
@ -1909,17 +1909,17 @@ func addKubeSystemPdbs(f *framework.Framework) (func(), error) {
labelMap := map[string]string{"k8s-app": pdbData.label}
pdbName := fmt.Sprintf("test-pdb-for-%v", pdbData.label)
minAvailable := intstr.FromInt(pdbData.minAvailable)
pdb := &policyv1beta1.PodDisruptionBudget{
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: pdbName,
Namespace: "kube-system",
},
Spec: policyv1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{MatchLabels: labelMap},
MinAvailable: &minAvailable,
},
}
_, err := f.ClientSet.PolicyV1beta1().PodDisruptionBudgets("kube-system").Create(context.TODO(), pdb, metav1.CreateOptions{})
_, err := f.ClientSet.PolicyV1().PodDisruptionBudgets("kube-system").Create(context.TODO(), pdb, metav1.CreateOptions{})
newPdbs = append(newPdbs, pdbName)
if err != nil {

View File

@ -28,7 +28,7 @@ import (
"github.com/onsi/ginkgo"
v1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
policyv1 "k8s.io/api/policy/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
@ -679,9 +679,9 @@ func (j *TestJig) AddRCAntiAffinity(rc *v1.ReplicationController) {
}
// CreatePDB returns a PodDisruptionBudget for the given ReplicationController, or returns an error if a PodDisruptionBudget isn't ready
func (j *TestJig) CreatePDB(rc *v1.ReplicationController) (*policyv1beta1.PodDisruptionBudget, error) {
func (j *TestJig) CreatePDB(rc *v1.ReplicationController) (*policyv1.PodDisruptionBudget, error) {
pdb := j.newPDBTemplate(rc)
newPdb, err := j.Client.PolicyV1beta1().PodDisruptionBudgets(j.Namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
newPdb, err := j.Client.PolicyV1().PodDisruptionBudgets(j.Namespace).Create(context.TODO(), pdb, metav1.CreateOptions{})
if err != nil {
return nil, fmt.Errorf("failed to create PDB %q %v", pdb.Name, err)
}
@ -692,19 +692,19 @@ func (j *TestJig) CreatePDB(rc *v1.ReplicationController) (*policyv1beta1.PodDis
return newPdb, nil
}
// newPDBTemplate returns the default policyv1beta1.PodDisruptionBudget object for
// newPDBTemplate returns the default policyv1.PodDisruptionBudget object for
// this j, but does not actually create the PDB. The default PDB specifies a
// MinAvailable of N-1 and matches the pods created by the RC.
func (j *TestJig) newPDBTemplate(rc *v1.ReplicationController) *policyv1beta1.PodDisruptionBudget {
func (j *TestJig) newPDBTemplate(rc *v1.ReplicationController) *policyv1.PodDisruptionBudget {
minAvailable := intstr.FromInt(int(*rc.Spec.Replicas) - 1)
pdb := &policyv1beta1.PodDisruptionBudget{
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Namespace: j.Namespace,
Name: j.Name,
Labels: j.Labels,
},
Spec: policyv1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{MatchLabels: j.Labels},
},
@ -762,7 +762,7 @@ func (j *TestJig) Scale(replicas int) error {
func (j *TestJig) waitForPdbReady() error {
timeout := 2 * time.Minute
for start := time.Now(); time.Since(start) < timeout; time.Sleep(2 * time.Second) {
pdb, err := j.Client.PolicyV1beta1().PodDisruptionBudgets(j.Namespace).Get(context.TODO(), j.Name, metav1.GetOptions{})
pdb, err := j.Client.PolicyV1().PodDisruptionBudgets(j.Namespace).Get(context.TODO(), j.Name, metav1.GetOptions{})
if err != nil {
return err
}

View File

@ -54,6 +54,7 @@ var statusData = map[schema.GroupVersionResource]string{
gvr("batch", "v1", "cronjobs"): `{"status": {"lastScheduleTime": null}}`,
gvr("batch", "v1beta1", "cronjobs"): `{"status": {"lastScheduleTime": null}}`,
gvr("storage.k8s.io", "v1", "volumeattachments"): `{"status": {"attached": true}}`,
gvr("policy", "v1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
gvr("policy", "v1beta1", "poddisruptionbudgets"): `{"status": {"currentHealthy": 5}}`,
gvr("certificates.k8s.io", "v1beta1", "certificatesigningrequests"): `{"status": {"conditions": [{"type": "MyStatus"}]}}`,
gvr("certificates.k8s.io", "v1", "certificatesigningrequests"): `{"status": {"conditions": [{"type": "MyStatus", "status": "True"}]}}`,

View File

@ -27,6 +27,7 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
v1 "k8s.io/api/core/v1"
policyv1 "k8s.io/api/policy/v1"
"k8s.io/api/policy/v1beta1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -81,7 +82,7 @@ func setup(t *testing.T) (*kubeapiservertesting.TestServer, *disruption.Disrupti
pdbc := disruption.NewDisruptionController(
informers.Core().V1().Pods(),
informers.Policy().V1beta1().PodDisruptionBudgets(),
informers.Policy().V1().PodDisruptionBudgets(),
informers.Core().V1().ReplicationControllers(),
informers.Apps().V1().ReplicaSets(),
informers.Apps().V1().Deployments(),
@ -113,7 +114,6 @@ func TestPDBWithScaleSubresource(t *testing.T) {
replicas := 4
maxUnavailable := int32(2)
podLabelValue := "test-crd"
resource := &unstructured.Unstructured{
Object: map[string]interface{}{
@ -134,40 +134,42 @@ func TestPDBWithScaleSubresource(t *testing.T) {
}
trueValue := true
ownerRef := metav1.OwnerReference{
Name: resource.GetName(),
Kind: crdDefinition.Spec.Names.Kind,
APIVersion: crdDefinition.Spec.Group + "/" + crdDefinition.Spec.Versions[0].Name,
UID: createdResource.GetUID(),
Controller: &trueValue,
ownerRefs := []metav1.OwnerReference{
{
Name: resource.GetName(),
Kind: crdDefinition.Spec.Names.Kind,
APIVersion: crdDefinition.Spec.Group + "/" + crdDefinition.Spec.Versions[0].Name,
UID: createdResource.GetUID(),
Controller: &trueValue,
},
}
for i := 0; i < replicas; i++ {
createPod(t, fmt.Sprintf("pod-%d", i), nsName, podLabelValue, clientSet, ownerRef)
createPod(t, fmt.Sprintf("pod-%d", i), nsName, map[string]string{"app": "test-crd"}, clientSet, ownerRefs)
}
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 4, v1.PodRunning)
pdb := &v1beta1.PodDisruptionBudget{
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pdb",
},
Spec: v1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
MaxUnavailable: &intstr.IntOrString{
Type: intstr.Int,
IntVal: maxUnavailable,
},
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"app": podLabelValue},
MatchLabels: map[string]string{"app": "test-crd"},
},
},
}
if _, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
if _, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
t.Errorf("Error creating PodDisruptionBudget: %v", err)
}
waitPDBStable(t, clientSet, 4, nsName, pdb.Name)
newPdb, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(nsName).Get(context.TODO(), pdb.Name, metav1.GetOptions{})
newPdb, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Get(context.TODO(), pdb.Name, metav1.GetOptions{})
if err != nil {
t.Errorf("Error getting PodDisruptionBudget: %v", err)
}
@ -183,15 +185,211 @@ func TestPDBWithScaleSubresource(t *testing.T) {
}
}
func createPod(t *testing.T, name, namespace, labelValue string, clientSet clientset.Interface, ownerRef metav1.OwnerReference) {
func TestEmptySelector(t *testing.T) {
testcases := []struct {
name string
createPDBFunc func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error
expectedCurrentHealthy int32
}{
{
name: "v1beta1 should not target any pods",
createPDBFunc: func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error {
pdb := &v1beta1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1beta1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{},
},
}
_, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{})
return err
},
expectedCurrentHealthy: 0,
},
{
name: "v1 should target all pods",
createPDBFunc: func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error {
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{},
},
}
_, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{})
return err
},
expectedCurrentHealthy: 4,
},
}
for i, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
s, pdbc, informers, clientSet, _, _ := setup(t)
defer s.TearDownFn()
nsName := fmt.Sprintf("pdb-empty-selector-%d", i)
createNs(t, nsName, clientSet)
stopCh := make(chan struct{})
informers.Start(stopCh)
go pdbc.Run(stopCh)
defer close(stopCh)
replicas := 4
minAvailable := intstr.FromInt(2)
for j := 0; j < replicas; j++ {
createPod(t, fmt.Sprintf("pod-%d", j), nsName, map[string]string{"app": "test-crd"},
clientSet, []metav1.OwnerReference{})
}
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 4, v1.PodRunning)
pdbName := "test-pdb"
if err := tc.createPDBFunc(clientSet, pdbName, nsName, minAvailable); err != nil {
t.Errorf("Error creating PodDisruptionBudget: %v", err)
}
waitPDBStable(t, clientSet, tc.expectedCurrentHealthy, nsName, pdbName)
newPdb, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Get(context.TODO(), pdbName, metav1.GetOptions{})
if err != nil {
t.Errorf("Error getting PodDisruptionBudget: %v", err)
}
if expected, found := tc.expectedCurrentHealthy, newPdb.Status.CurrentHealthy; expected != found {
t.Errorf("Expected %d, but found %d", expected, found)
}
})
}
}
func TestSelectorsForPodsWithoutLabels(t *testing.T) {
testcases := []struct {
name string
createPDBFunc func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error
expectedCurrentHealthy int32
}{
{
name: "pods with no labels can be targeted by v1 PDBs with empty selector",
createPDBFunc: func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error {
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{},
},
}
_, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{})
return err
},
expectedCurrentHealthy: 1,
},
{
name: "pods with no labels can be targeted by v1 PDBs with DoesNotExist selector",
createPDBFunc: func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error {
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "DoesNotExist",
Operator: metav1.LabelSelectorOpDoesNotExist,
},
},
},
},
}
_, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{})
return err
},
expectedCurrentHealthy: 1,
},
{
name: "pods with no labels can be targeted by v1beta1 PDBs with DoesNotExist selector",
createPDBFunc: func(clientSet clientset.Interface, name, nsName string, minAvailable intstr.IntOrString) error {
pdb := &v1beta1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1beta1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "DoesNotExist",
Operator: metav1.LabelSelectorOpDoesNotExist,
},
},
},
},
}
_, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(nsName).Create(context.TODO(), pdb, metav1.CreateOptions{})
return err
},
expectedCurrentHealthy: 1,
},
}
for i, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
s, pdbc, informers, clientSet, _, _ := setup(t)
defer s.TearDownFn()
nsName := fmt.Sprintf("pdb-selectors-%d", i)
createNs(t, nsName, clientSet)
stopCh := make(chan struct{})
informers.Start(stopCh)
go pdbc.Run(stopCh)
defer close(stopCh)
minAvailable := intstr.FromInt(1)
// Create the PDB first and wait for it to settle.
pdbName := "test-pdb"
if err := tc.createPDBFunc(clientSet, pdbName, nsName, minAvailable); err != nil {
t.Errorf("Error creating PodDisruptionBudget: %v", err)
}
waitPDBStable(t, clientSet, 0, nsName, pdbName)
// Create a pod and wait for it be reach the running phase.
createPod(t, "pod", nsName, map[string]string{}, clientSet, []metav1.OwnerReference{})
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 1, v1.PodRunning)
// Then verify that the added pod are picked up by the disruption controller.
waitPDBStable(t, clientSet, 1, nsName, pdbName)
newPdb, err := clientSet.PolicyV1().PodDisruptionBudgets(nsName).Get(context.TODO(), pdbName, metav1.GetOptions{})
if err != nil {
t.Errorf("Error getting PodDisruptionBudget: %v", err)
}
if expected, found := tc.expectedCurrentHealthy, newPdb.Status.CurrentHealthy; expected != found {
t.Errorf("Expected %d, but found %d", expected, found)
}
})
}
}
func createPod(t *testing.T, name, namespace string, labels map[string]string, clientSet clientset.Interface, ownerRefs []metav1.OwnerReference) {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: map[string]string{"app": labelValue},
OwnerReferences: []metav1.OwnerReference{
ownerRef,
},
Name: name,
Namespace: namespace,
Labels: labels,
OwnerReferences: ownerRefs,
},
Spec: v1.PodSpec{
Containers: []v1.Container{
@ -271,7 +469,7 @@ func waitPDBStable(t *testing.T, clientSet clientset.Interface, podNum int32, ns
if err != nil {
return false, err
}
if pdb.Status.CurrentHealthy != podNum {
if pdb.Status.ObservedGeneration == 0 || pdb.Status.CurrentHealthy != podNum {
return false, nil
}
return true, nil

View File

@ -265,6 +265,14 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes
},
// --
// k8s.io/kubernetes/pkg/apis/policy/v1
gvr("policy", "v1", "poddisruptionbudgets"): {
Stub: `{"metadata": {"name": "pdbv1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,
ExpectedEtcdPath: "/registry/poddisruptionbudgets/" + namespace + "/pdbv1",
ExpectedGVK: gvkP("policy", "v1beta1", "PodDisruptionBudget"),
},
// --
// k8s.io/kubernetes/pkg/apis/policy/v1beta1
gvr("policy", "v1beta1", "poddisruptionbudgets"): {
Stub: `{"metadata": {"name": "pdb1"}, "spec": {"selector": {"matchLabels": {"anokkey": "anokvalue"}}}}`,

View File

@ -19,7 +19,6 @@ package evictions
import (
"context"
"fmt"
"net/http/httptest"
"reflect"
"sync"
@ -28,7 +27,8 @@ import (
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/api/policy/v1beta1"
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"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
@ -95,7 +95,7 @@ func TestConcurrentEvictionRequests(t *testing.T) {
waitToObservePods(t, informers.Core().V1().Pods().Informer(), numOfEvictions, v1.PodRunning)
pdb := newPDB()
if _, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(ns.Name).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
if _, err := clientSet.PolicyV1().PodDisruptionBudgets(ns.Name).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
t.Errorf("Failed to create PodDisruptionBudget: %v", err)
}
@ -110,7 +110,7 @@ func TestConcurrentEvictionRequests(t *testing.T) {
go func(id int, errCh chan error) {
defer wg.Done()
podName := fmt.Sprintf(podNameFormat, id)
eviction := newEviction(ns.Name, podName, deleteOption)
eviction := newV1beta1Eviction(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)
@ -208,7 +208,7 @@ func TestTerminalPodEviction(t *testing.T) {
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 1, v1.PodSucceeded)
pdb := newPDB()
if _, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(ns.Name).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
if _, err := clientSet.PolicyV1().PodDisruptionBudgets(ns.Name).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
t.Errorf("Failed to create PodDisruptionBudget: %v", err)
}
@ -219,7 +219,7 @@ func TestTerminalPodEviction(t *testing.T) {
t.Fatalf("Error while listing pod disruption budget")
}
oldPdb := pdbList.Items[0]
eviction := newEviction(ns.Name, pod.Name, deleteOption)
eviction := newV1beta1Eviction(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)
switch {
@ -292,12 +292,12 @@ func addPodConditionReady(pod *v1.Pod) {
}
}
func newPDB() *v1beta1.PodDisruptionBudget {
return &v1beta1.PodDisruptionBudget{
func newPDB() *policyv1.PodDisruptionBudget {
return &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pdb",
},
Spec: v1beta1.PodDisruptionBudgetSpec{
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &intstr.IntOrString{
Type: intstr.Int,
IntVal: 0,
@ -309,8 +309,8 @@ func newPDB() *v1beta1.PodDisruptionBudget {
}
}
func newEviction(ns, evictionName string, deleteOption metav1.DeleteOptions) *v1beta1.Eviction {
return &v1beta1.Eviction{
func newV1beta1Eviction(ns, evictionName string, deleteOption metav1.DeleteOptions) *policyv1beta1.Eviction {
return &policyv1beta1.Eviction{
TypeMeta: metav1.TypeMeta{
APIVersion: "Policy/v1beta1",
Kind: "Eviction",
@ -348,7 +348,7 @@ func rmSetup(t *testing.T) (*httptest.Server, framework.CloseFunc, *disruption.D
rm := disruption.NewDisruptionController(
informers.Core().V1().Pods(),
informers.Policy().V1beta1().PodDisruptionBudgets(),
informers.Policy().V1().PodDisruptionBudgets(),
informers.Core().V1().ReplicationControllers(),
informers.Apps().V1().ReplicaSets(),
informers.Apps().V1().Deployments(),

View File

@ -62,7 +62,7 @@ func initDisruptionController(t *testing.T, testCtx *testutils.TestContext) *dis
dc := disruption.NewDisruptionController(
informers.Core().V1().Pods(),
informers.Policy().V1beta1().PodDisruptionBudgets(),
informers.Policy().V1().PodDisruptionBudgets(),
informers.Core().V1().ReplicationControllers(),
informers.Apps().V1().ReplicaSets(),
informers.Apps().V1().Deployments(),

6
vendor/modules.txt vendored
View File

@ -1614,6 +1614,7 @@ k8s.io/api/networking/v1beta1
k8s.io/api/node/v1
k8s.io/api/node/v1alpha1
k8s.io/api/node/v1beta1
k8s.io/api/policy/v1
k8s.io/api/policy/v1beta1
k8s.io/api/rbac/v1
k8s.io/api/rbac/v1alpha1
@ -1931,6 +1932,7 @@ k8s.io/client-go/applyconfigurations/networking/v1beta1
k8s.io/client-go/applyconfigurations/node/v1
k8s.io/client-go/applyconfigurations/node/v1alpha1
k8s.io/client-go/applyconfigurations/node/v1beta1
k8s.io/client-go/applyconfigurations/policy/v1
k8s.io/client-go/applyconfigurations/policy/v1beta1
k8s.io/client-go/applyconfigurations/rbac/v1
k8s.io/client-go/applyconfigurations/rbac/v1alpha1
@ -1993,6 +1995,7 @@ k8s.io/client-go/informers/node/v1
k8s.io/client-go/informers/node/v1alpha1
k8s.io/client-go/informers/node/v1beta1
k8s.io/client-go/informers/policy
k8s.io/client-go/informers/policy/v1
k8s.io/client-go/informers/policy/v1beta1
k8s.io/client-go/informers/rbac
k8s.io/client-go/informers/rbac/v1
@ -2073,6 +2076,8 @@ k8s.io/client-go/kubernetes/typed/node/v1alpha1
k8s.io/client-go/kubernetes/typed/node/v1alpha1/fake
k8s.io/client-go/kubernetes/typed/node/v1beta1
k8s.io/client-go/kubernetes/typed/node/v1beta1/fake
k8s.io/client-go/kubernetes/typed/policy/v1
k8s.io/client-go/kubernetes/typed/policy/v1/fake
k8s.io/client-go/kubernetes/typed/policy/v1beta1
k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake
k8s.io/client-go/kubernetes/typed/rbac/v1
@ -2121,6 +2126,7 @@ k8s.io/client-go/listers/networking/v1beta1
k8s.io/client-go/listers/node/v1
k8s.io/client-go/listers/node/v1alpha1
k8s.io/client-go/listers/node/v1beta1
k8s.io/client-go/listers/policy/v1
k8s.io/client-go/listers/policy/v1beta1
k8s.io/client-go/listers/rbac/v1
k8s.io/client-go/listers/rbac/v1alpha1