mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #113375 from atiratree/PodHealthyPolicy-api
api: add unhealthyPodEvictionPolicy for PDBs
This commit is contained in:
commit
cc704f9778
4
api/openapi-spec/swagger.json
generated
4
api/openapi-spec/swagger.json
generated
@ -12305,6 +12305,10 @@
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector",
|
||||
"description": "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.",
|
||||
"x-kubernetes-patch-strategy": "replace"
|
||||
},
|
||||
"unhealthyPodEvictionPolicy": {
|
||||
"description": "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
@ -121,6 +121,10 @@
|
||||
],
|
||||
"description": "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.",
|
||||
"x-kubernetes-patch-strategy": "replace"
|
||||
},
|
||||
"unhealthyPodEvictionPolicy": {
|
||||
"description": "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
@ -42,8 +42,56 @@ type PodDisruptionBudgetSpec struct {
|
||||
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
|
||||
// +optional
|
||||
MaxUnavailable *intstr.IntOrString
|
||||
|
||||
// UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction. Current implementation considers healthy pods,
|
||||
// as pods that have status.conditions item with type="Ready",status="True".
|
||||
//
|
||||
// Valid policies are IfHealthyBudget and AlwaysAllow.
|
||||
// If no policy is specified, the default behavior will be used,
|
||||
// which corresponds to the IfHealthyBudget policy.
|
||||
//
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// Additional policies may be added in the future.
|
||||
// Clients making eviction decisions should disallow eviction of unhealthy pods
|
||||
// if they encounter an unrecognized policy in this field.
|
||||
//
|
||||
// This field is alpha-level. The eviction API uses this field when
|
||||
// the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).
|
||||
// +optional
|
||||
UnhealthyPodEvictionPolicy *UnhealthyPodEvictionPolicyType
|
||||
}
|
||||
|
||||
// UnhealthyPodEvictionPolicyType defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction.
|
||||
// +enum
|
||||
type UnhealthyPodEvictionPolicyType string
|
||||
|
||||
const (
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
IfHealthyBudget UnhealthyPodEvictionPolicyType = "IfHealthyBudget"
|
||||
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
AlwaysAllow UnhealthyPodEvictionPolicyType = "AlwaysAllow"
|
||||
)
|
||||
|
||||
// PodDisruptionBudgetStatus represents information about the status of a
|
||||
// PodDisruptionBudget. Status may trail the actual state of a system.
|
||||
type PodDisruptionBudgetStatus struct {
|
||||
|
2
pkg/apis/policy/v1/zz_generated.conversion.go
generated
2
pkg/apis/policy/v1/zz_generated.conversion.go
generated
@ -187,6 +187,7 @@ func autoConvert_v1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSpec(in
|
||||
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
|
||||
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
|
||||
out.UnhealthyPodEvictionPolicy = (*policy.UnhealthyPodEvictionPolicyType)(unsafe.Pointer(in.UnhealthyPodEvictionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -199,6 +200,7 @@ func autoConvert_policy_PodDisruptionBudgetSpec_To_v1_PodDisruptionBudgetSpec(in
|
||||
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
|
||||
out.Selector = (*metav1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
|
||||
out.UnhealthyPodEvictionPolicy = (*v1.UnhealthyPodEvictionPolicyType)(unsafe.Pointer(in.UnhealthyPodEvictionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,7 @@ func autoConvert_v1beta1_PodDisruptionBudgetSpec_To_policy_PodDisruptionBudgetSp
|
||||
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
|
||||
out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
|
||||
out.UnhealthyPodEvictionPolicy = (*policy.UnhealthyPodEvictionPolicyType)(unsafe.Pointer(in.UnhealthyPodEvictionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -464,6 +465,7 @@ func autoConvert_policy_PodDisruptionBudgetSpec_To_v1beta1_PodDisruptionBudgetSp
|
||||
out.MinAvailable = (*intstr.IntOrString)(unsafe.Pointer(in.MinAvailable))
|
||||
out.Selector = (*v1.LabelSelector)(unsafe.Pointer(in.Selector))
|
||||
out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable))
|
||||
out.UnhealthyPodEvictionPolicy = (*v1beta1.UnhealthyPodEvictionPolicyType)(unsafe.Pointer(in.UnhealthyPodEvictionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,11 @@ const (
|
||||
seccompAllowedProfilesAnnotationKey = "seccomp.security.alpha.kubernetes.io/allowedProfileNames"
|
||||
)
|
||||
|
||||
var supportedUnhealthyPodEvictionPolicies = sets.NewString(
|
||||
string(policy.IfHealthyBudget),
|
||||
string(policy.AlwaysAllow),
|
||||
)
|
||||
|
||||
type PodDisruptionBudgetValidationOptions struct {
|
||||
AllowInvalidLabelValueInSelector bool
|
||||
}
|
||||
@ -78,6 +83,10 @@ func ValidatePodDisruptionBudgetSpec(spec policy.PodDisruptionBudgetSpec, opts P
|
||||
|
||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, labelSelectorValidationOptions, fldPath.Child("selector"))...)
|
||||
|
||||
if spec.UnhealthyPodEvictionPolicy != nil && !supportedUnhealthyPodEvictionPolicies.Has(string(*spec.UnhealthyPodEvictionPolicy)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("unhealthyPodEvictionPolicy"), *spec.UnhealthyPodEvictionPolicy, supportedUnhealthyPodEvictionPolicies.List()))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,63 @@ func TestValidateMinAvailablePodAndMaxUnavailableDisruptionBudgetSpec(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUnhealthyPodEvictionPolicyDisruptionBudgetSpec(t *testing.T) {
|
||||
c1 := intstr.FromString("10%")
|
||||
alwaysAllowPolicy := policy.AlwaysAllow
|
||||
invalidPolicy := policy.UnhealthyPodEvictionPolicyType("Invalid")
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
pdbSpec policy.PodDisruptionBudgetSpec
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid nil UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: nil,
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid UnhealthyPodEvictionPolicy",
|
||||
pdbSpec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &c1,
|
||||
UnhealthyPodEvictionPolicy: &invalidPolicy,
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := ValidatePodDisruptionBudgetSpec(tc.pdbSpec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
|
||||
if len(errs) == 0 && tc.expectErr {
|
||||
t.Errorf("unexpected success for %v", tc.pdbSpec)
|
||||
}
|
||||
if len(errs) != 0 && !tc.expectErr {
|
||||
t.Errorf("unexpected failure for %v", tc.pdbSpec)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePodDisruptionBudgetStatus(t *testing.T) {
|
||||
const expectNoErrors = false
|
||||
const expectErrors = true
|
||||
|
5
pkg/apis/policy/zz_generated.deepcopy.go
generated
5
pkg/apis/policy/zz_generated.deepcopy.go
generated
@ -239,6 +239,11 @@ func (in *PodDisruptionBudgetSpec) DeepCopyInto(out *PodDisruptionBudgetSpec) {
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
if in.UnhealthyPodEvictionPolicy != nil {
|
||||
in, out := &in.UnhealthyPodEvictionPolicy, &out.UnhealthyPodEvictionPolicy
|
||||
*out = new(UnhealthyPodEvictionPolicyType)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -633,6 +633,13 @@ const (
|
||||
// Permits kubelet to run with swap enabled
|
||||
NodeSwap featuregate.Feature = "NodeSwap"
|
||||
|
||||
// owner: @mortent, @atiratree, @ravig
|
||||
// kep: http://kep.k8s.io/3018
|
||||
// alpha: v1.26
|
||||
//
|
||||
// Enables PDBUnhealthyPodEvictionPolicy for PodDisruptionBudgets
|
||||
PDBUnhealthyPodEvictionPolicy featuregate.Feature = "PDBUnhealthyPodEvictionPolicy"
|
||||
|
||||
// owner: @haircommander
|
||||
// kep: https://kep.k8s.io/2364
|
||||
// alpha: v1.23
|
||||
@ -1062,6 +1069,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
NodeSwap: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
PDBUnhealthyPodEvictionPolicy: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
PodAndContainerStatsFromCRI: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
PodDeletionCost: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
14
pkg/generated/openapi/zz_generated.openapi.go
generated
14
pkg/generated/openapi/zz_generated.openapi.go
generated
@ -38300,6 +38300,13 @@ func schema_k8sio_api_policy_v1_PodDisruptionBudgetSpec(ref common.ReferenceCall
|
||||
Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"),
|
||||
},
|
||||
},
|
||||
"unhealthyPodEvictionPolicy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -38737,6 +38744,13 @@ func schema_k8sio_api_policy_v1beta1_PodDisruptionBudgetSpec(ref common.Referenc
|
||||
Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"),
|
||||
},
|
||||
},
|
||||
"unhealthyPodEvictionPolicy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -226,11 +226,25 @@ func (r *EvictionREST) Create(ctx context.Context, name string, obj runtime.Obje
|
||||
pdb := &pdbs[0]
|
||||
pdbName = pdb.Name
|
||||
|
||||
// If the pod is not ready, it doesn't count towards healthy and we should not decrement
|
||||
if !podutil.IsPodReady(pod) && pdb.Status.CurrentHealthy >= pdb.Status.DesiredHealthy && pdb.Status.DesiredHealthy > 0 {
|
||||
// IsPodReady is the current implementation of IsHealthy
|
||||
// If the pod is healthy, it should be guarded by the PDB.
|
||||
if !podutil.IsPodReady(pod) {
|
||||
if feature.DefaultFeatureGate.Enabled(features.PDBUnhealthyPodEvictionPolicy) {
|
||||
if pdb.Spec.UnhealthyPodEvictionPolicy != nil && *pdb.Spec.UnhealthyPodEvictionPolicy == policyv1.AlwaysAllow {
|
||||
// Delete the unhealthy pod, it doesn't count towards currentHealthy and desiredHealthy and we should not decrement disruptionsAllowed.
|
||||
updateDeletionOptions = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// default nil and IfHealthyBudget policy
|
||||
if pdb.Status.CurrentHealthy >= pdb.Status.DesiredHealthy && pdb.Status.DesiredHealthy > 0 {
|
||||
// Delete the unhealthy pod, it doesn't count towards currentHealthy and desiredHealthy and we should not decrement disruptionsAllowed.
|
||||
// Application guarded by the PDB is not disrupted at the moment and deleting unhealthy (unready) pod will not disrupt it.
|
||||
updateDeletionOptions = true
|
||||
return nil
|
||||
}
|
||||
// confirm no disruptions allowed in checkAndDecrement
|
||||
}
|
||||
|
||||
refresh := false
|
||||
err = retry.RetryOnConflict(EvictionsRetry, func() error {
|
||||
@ -264,12 +278,12 @@ func (r *EvictionREST) Create(ctx context.Context, name string, obj runtime.Obje
|
||||
}
|
||||
|
||||
// At this point there was either no PDB or we succeeded in decrementing or
|
||||
// the pod was unready and we have enough healthy replicas
|
||||
// the pod was unhealthy (unready) and we have enough healthy replicas
|
||||
|
||||
deleteOptions := originalDeleteOptions
|
||||
|
||||
// Set deleteOptions.Preconditions.ResourceVersion to ensure
|
||||
// the pod hasn't been considered ready since we calculated
|
||||
// the pod hasn't been considered healthy (ready) since we calculated
|
||||
if updateDeletionOptions {
|
||||
// Take a copy so we can compare to client-provied Options later.
|
||||
deleteOptions = deleteOptions.DeepCopy()
|
||||
@ -351,7 +365,7 @@ func shouldEnforceResourceVersion(pod *api.Pod) bool {
|
||||
return false
|
||||
}
|
||||
// Return true for all other pods to ensure we don't race against a pod becoming
|
||||
// ready and violating PDBs.
|
||||
// healthy (ready) and violating PDBs.
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,9 @@ package storage
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
policyv1 "k8s.io/api/policy/v1"
|
||||
@ -31,21 +34,25 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
podapi "k8s.io/kubernetes/pkg/api/pod"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func TestEviction(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
pdbs []runtime.Object
|
||||
policies []*policyv1.UnhealthyPodEvictionPolicyType
|
||||
eviction *policy.Eviction
|
||||
|
||||
badNameInURL bool
|
||||
|
||||
expectError bool
|
||||
expectError string
|
||||
expectDeleted bool
|
||||
podPhase api.PodPhase
|
||||
podName string
|
||||
@ -58,9 +65,10 @@ func TestEviction(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t1", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "Cannot evict pod as it would violate the pod's disruption budget.: TooManyRequests: The disruption budget foo needs 0 healthy pods and has 0 currently",
|
||||
podPhase: api.PodRunning,
|
||||
podName: "t1",
|
||||
policies: []*policyv1.UnhealthyPodEvictionPolicyType{nil, unhealthyPolicyPtr(policyv1.IfHealthyBudget)}, // AlwaysAllow would terminate the pod since Running pods are not guarded by this policy
|
||||
},
|
||||
{
|
||||
name: "matching pdbs with no disruptions allowed, pod pending",
|
||||
@ -70,7 +78,7 @@ func TestEviction(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t2", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podPhase: api.PodPending,
|
||||
expectDeleted: true,
|
||||
podName: "t2",
|
||||
@ -83,7 +91,7 @@ func TestEviction(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t3", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podPhase: api.PodSucceeded,
|
||||
expectDeleted: true,
|
||||
podName: "t3",
|
||||
@ -96,7 +104,7 @@ func TestEviction(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t4", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podPhase: api.PodFailed,
|
||||
expectDeleted: true,
|
||||
podName: "t4",
|
||||
@ -132,13 +140,29 @@ func TestEviction(t *testing.T) {
|
||||
}},
|
||||
badNameInURL: true,
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t7", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "name in URL does not match name in Eviction object: BadRequest",
|
||||
podName: "t7",
|
||||
},
|
||||
}
|
||||
|
||||
for _, unhealthyPodEvictionPolicy := range []*policyv1.UnhealthyPodEvictionPolicyType{nil, unhealthyPolicyPtr(policyv1.IfHealthyBudget), unhealthyPolicyPtr(policyv1.AlwaysAllow)} {
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if len(tc.policies) > 0 && !hasUnhealthyPolicy(tc.policies, unhealthyPodEvictionPolicy) {
|
||||
// unhealthyPodEvictionPolicy is not covered by this test
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%v with %v policy", tc.name, unhealthyPolicyStr(unhealthyPodEvictionPolicy)), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, true)()
|
||||
|
||||
// same test runs multiple times, make copy of objects to have unique ones
|
||||
evictionCopy := tc.eviction.DeepCopy()
|
||||
var pdbsCopy []runtime.Object
|
||||
for _, pdb := range tc.pdbs {
|
||||
pdbCopy := pdb.DeepCopyObject()
|
||||
pdbCopy.(*policyv1.PodDisruptionBudget).Spec.UnhealthyPodEvictionPolicy = unhealthyPodEvictionPolicy
|
||||
pdbsCopy = append(pdbsCopy, pdbCopy)
|
||||
}
|
||||
|
||||
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||
storage, _, statusStorage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
@ -160,7 +184,7 @@ func TestEviction(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
client := fake.NewSimpleClientset(tc.pdbs...)
|
||||
client := fake.NewSimpleClientset(pdbsCopy...)
|
||||
evictionRest := newEvictionStorage(storage.Store, client.PolicyV1())
|
||||
|
||||
name := pod.Name
|
||||
@ -168,10 +192,10 @@ func TestEviction(t *testing.T) {
|
||||
name += "bad-name"
|
||||
}
|
||||
|
||||
_, err := evictionRest.Create(testContext, name, tc.eviction, nil, &metav1.CreateOptions{})
|
||||
//_, err = evictionRest.Create(testContext, name, tc.eviction, nil, &metav1.CreateOptions{})
|
||||
if (err != nil) != tc.expectError {
|
||||
t.Errorf("expected error=%v, got %v; name %v", tc.expectError, err, pod.Name)
|
||||
_, err := evictionRest.Create(testContext, name, evictionCopy, nil, &metav1.CreateOptions{})
|
||||
gotErr := errToString(err)
|
||||
if gotErr != tc.expectError {
|
||||
t.Errorf("error mismatch: expected %v, got %v; name %v", tc.expectError, gotErr, pod.Name)
|
||||
return
|
||||
}
|
||||
if tc.badNameInURL {
|
||||
@ -183,7 +207,7 @@ func TestEviction(t *testing.T) {
|
||||
t.Errorf("got unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
if tc.expectError {
|
||||
if tc.expectError != "" {
|
||||
return
|
||||
}
|
||||
|
||||
@ -209,14 +233,16 @@ func TestEviction(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvictionIngorePDB(t *testing.T) {
|
||||
func TestEvictionIgnorePDB(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
pdbs []runtime.Object
|
||||
policies []*policyv1.UnhealthyPodEvictionPolicyType
|
||||
eviction *policy.Eviction
|
||||
|
||||
expectError bool
|
||||
expectError string
|
||||
podPhase api.PodPhase
|
||||
podName string
|
||||
expectedDeleteCount int
|
||||
@ -231,7 +257,7 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t1", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podPhase: api.PodPending,
|
||||
podName: "t1",
|
||||
expectedDeleteCount: 3,
|
||||
@ -247,10 +273,30 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t2", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "Cannot evict pod as it would violate the pod's disruption budget.: TooManyRequests: The disruption budget foo needs 0 healthy pods and has 0 currently",
|
||||
podPhase: api.PodPending,
|
||||
podName: "t2",
|
||||
expectedDeleteCount: 1,
|
||||
policies: []*policyv1.UnhealthyPodEvictionPolicyType{nil, unhealthyPolicyPtr(policyv1.IfHealthyBudget)}, // AlwaysAllow does not continueToPDBs, but straight to deletion
|
||||
},
|
||||
{
|
||||
name: "pdbs No disruptions allowed, pod pending, first delete conflict, pod becomes running, skip PDB check, conflict",
|
||||
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
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: "Cannot evict pod as it would violate the pod's disruption budget.: TooManyRequests: The disruption budget foo is still being processed by the server.",
|
||||
podPhase: api.PodPending,
|
||||
podName: "t2",
|
||||
podTerminating: false,
|
||||
expectedDeleteCount: 2,
|
||||
prc: &api.PodCondition{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionFalse,
|
||||
},
|
||||
policies: []*policyv1.UnhealthyPodEvictionPolicyType{unhealthyPolicyPtr(policyv1.AlwaysAllow)}, // nil, IfHealthyBudget continueToPDBs
|
||||
},
|
||||
{
|
||||
name: "pdbs disruptions allowed, pod pending, first delete conflict, pod becomes running, continueToPDBs",
|
||||
@ -260,10 +306,11 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 1},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t3", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podPhase: api.PodPending,
|
||||
podName: "t3",
|
||||
expectedDeleteCount: 2,
|
||||
policies: []*policyv1.UnhealthyPodEvictionPolicyType{nil, unhealthyPolicyPtr(policyv1.IfHealthyBudget)}, // AlwaysAllow does not continueToPDBs, but straight to deletion if pod not healthy (ready)
|
||||
},
|
||||
{
|
||||
name: "pod pending, always conflict on delete",
|
||||
@ -273,7 +320,7 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t4", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: `Operation cannot be fulfilled on tests "2": message: Conflict`,
|
||||
podPhase: api.PodPending,
|
||||
podName: "t4",
|
||||
expectedDeleteCount: EvictionsRetry.Steps,
|
||||
@ -286,7 +333,7 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t5", Namespace: "default"}, DeleteOptions: metav1.NewRVDeletionPrecondition("userProvided")},
|
||||
expectError: true,
|
||||
expectError: `Operation cannot be fulfilled on tests "2": message: Conflict`,
|
||||
podPhase: api.PodPending,
|
||||
podName: "t5",
|
||||
expectedDeleteCount: 1,
|
||||
@ -299,7 +346,7 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t6", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(300)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podName: "t6",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: true,
|
||||
@ -310,14 +357,14 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
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.
|
||||
// This simulates 3 pods expected, our pod healthy, unhealthy pod is not ours.
|
||||
DisruptionsAllowed: 0,
|
||||
CurrentHealthy: 2,
|
||||
DesiredHealthy: 2,
|
||||
},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t7", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "Cannot evict pod as it would violate the pod's disruption budget.: TooManyRequests: The disruption budget foo needs 2 healthy pods and has 2 currently",
|
||||
podName: "t7",
|
||||
expectedDeleteCount: 0,
|
||||
podTerminating: false,
|
||||
@ -327,20 +374,42 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "matching pdbs with disruptions allowed, pod running, pod healthy, healthy pod ours, deletes pod by honoring the PDB",
|
||||
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
|
||||
Status: policyv1.PodDisruptionBudgetStatus{
|
||||
DisruptionsAllowed: 1,
|
||||
CurrentHealthy: 3,
|
||||
DesiredHealthy: 3,
|
||||
},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t8", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: "",
|
||||
podName: "t8",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: false,
|
||||
podPhase: api.PodRunning,
|
||||
prc: &api.PodCondition{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionTrue,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "matching pdbs with no disruptions allowed, pod running, pod unhealthy, unhealthy pod ours",
|
||||
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
|
||||
Status: policyv1.PodDisruptionBudgetStatus{
|
||||
// This simulates 3 pods desired, our pod unhealthy
|
||||
// This simulates 3 pods expected, our pod unhealthy
|
||||
DisruptionsAllowed: 0,
|
||||
CurrentHealthy: 2,
|
||||
DesiredHealthy: 2,
|
||||
},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t8", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: false,
|
||||
expectError: "",
|
||||
podName: "t8",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: false,
|
||||
@ -350,6 +419,25 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
Status: api.ConditionFalse,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "matching pdbs with no disruptions allowed, pod running, pod unhealthy, unhealthy pod ours, skips the PDB check and deletes",
|
||||
pdbs: []runtime.Object{&policyv1.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
|
||||
Status: policyv1.PodDisruptionBudgetStatus{DisruptionsAllowed: 0},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t8", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: "",
|
||||
podName: "t8",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: false,
|
||||
podPhase: api.PodRunning,
|
||||
prc: &api.PodCondition{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionFalse,
|
||||
},
|
||||
policies: []*policyv1.UnhealthyPodEvictionPolicyType{unhealthyPolicyPtr(policyv1.AlwaysAllow)}, // nil, IfHealthyBudget would not skip the PDB check
|
||||
},
|
||||
{
|
||||
// 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",
|
||||
@ -357,14 +445,14 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
|
||||
Status: policyv1.PodDisruptionBudgetStatus{
|
||||
// This simulates 3 pods desired, our pod unhealthy
|
||||
// This simulates 3 pods expected, our pod unhealthy
|
||||
DisruptionsAllowed: 0,
|
||||
CurrentHealthy: 2,
|
||||
DesiredHealthy: 2,
|
||||
},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t9", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "Cannot evict pod as it would violate the pod's disruption budget.: TooManyRequests: The disruption budget foo is still being processed by the server.",
|
||||
podName: "t9",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: false,
|
||||
@ -381,14 +469,14 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||
Spec: policyv1.PodDisruptionBudgetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "true"}}},
|
||||
Status: policyv1.PodDisruptionBudgetStatus{
|
||||
// This simulates 3 pods desired, our pod unhealthy
|
||||
// This simulates 3 pods expected, our pod unhealthy
|
||||
DisruptionsAllowed: 0,
|
||||
CurrentHealthy: 2,
|
||||
DesiredHealthy: 2,
|
||||
},
|
||||
}},
|
||||
eviction: &policy.Eviction{ObjectMeta: metav1.ObjectMeta{Name: "t10", Namespace: "default"}, DeleteOptions: metav1.NewDeleteOptions(0)},
|
||||
expectError: true,
|
||||
expectError: "test designed to error: BadRequest",
|
||||
podName: "t10",
|
||||
expectedDeleteCount: 1,
|
||||
podTerminating: false,
|
||||
@ -400,8 +488,25 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, unhealthyPodEvictionPolicy := range []*policyv1.UnhealthyPodEvictionPolicyType{unhealthyPolicyPtr(policyv1.AlwaysAllow), nil, unhealthyPolicyPtr(policyv1.IfHealthyBudget)} {
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if len(tc.policies) > 0 && !hasUnhealthyPolicy(tc.policies, unhealthyPodEvictionPolicy) {
|
||||
// unhealthyPodEvictionPolicy is not covered by this test
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("%v with %v policy", tc.name, unhealthyPolicyStr(unhealthyPodEvictionPolicy)), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, true)()
|
||||
|
||||
// same test runs 3 times, make copy of objects to have unique ones
|
||||
evictionCopy := tc.eviction.DeepCopy()
|
||||
prcCopy := tc.prc.DeepCopy()
|
||||
var pdbsCopy []runtime.Object
|
||||
for _, pdb := range tc.pdbs {
|
||||
pdbCopy := pdb.DeepCopyObject()
|
||||
pdbCopy.(*policyv1.PodDisruptionBudget).Spec.UnhealthyPodEvictionPolicy = unhealthyPodEvictionPolicy
|
||||
pdbsCopy = append(pdbsCopy, pdbCopy)
|
||||
}
|
||||
|
||||
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceDefault)
|
||||
ms := &mockStore{
|
||||
deleteCount: 0,
|
||||
@ -422,30 +527,31 @@ func TestEvictionIngorePDB(t *testing.T) {
|
||||
|
||||
// Setup pod condition
|
||||
if tc.prc != nil {
|
||||
if !podapi.UpdatePodCondition(&pod.Status, tc.prc) {
|
||||
if !podapi.UpdatePodCondition(&pod.Status, prcCopy) {
|
||||
t.Fatalf("Unable to update pod ready condition")
|
||||
}
|
||||
}
|
||||
|
||||
client := fake.NewSimpleClientset(tc.pdbs...)
|
||||
client := fake.NewSimpleClientset(pdbsCopy...)
|
||||
evictionRest := newEvictionStorage(ms, client.PolicyV1())
|
||||
|
||||
name := pod.Name
|
||||
ms.pod = pod
|
||||
|
||||
_, err := evictionRest.Create(testContext, name, tc.eviction, nil, &metav1.CreateOptions{})
|
||||
if (err != nil) != tc.expectError {
|
||||
t.Errorf("expected error=%v, got %v; name %v", tc.expectError, err, pod.Name)
|
||||
_, err := evictionRest.Create(testContext, name, evictionCopy, nil, &metav1.CreateOptions{})
|
||||
gotErr := errToString(err)
|
||||
if gotErr != tc.expectError {
|
||||
t.Errorf("error mismatch: expected %v, got %v; name %v", tc.expectError, gotErr, pod.Name)
|
||||
return
|
||||
}
|
||||
|
||||
if tc.expectedDeleteCount != ms.deleteCount {
|
||||
t.Errorf("expected delete count=%v, got %v; name %v", tc.expectedDeleteCount, ms.deleteCount, pod.Name)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvictionDryRun(t *testing.T) {
|
||||
testcases := []struct {
|
||||
@ -692,3 +798,41 @@ func (ms *mockStore) ConvertToTable(ctx context.Context, object runtime.Object,
|
||||
|
||||
func (ms *mockStore) Destroy() {
|
||||
}
|
||||
|
||||
func unhealthyPolicyPtr(unhealthyPodEvictionPolicy policyv1.UnhealthyPodEvictionPolicyType) *policyv1.UnhealthyPodEvictionPolicyType {
|
||||
return &unhealthyPodEvictionPolicy
|
||||
}
|
||||
|
||||
func unhealthyPolicyStr(unhealthyPodEvictionPolicy *policyv1.UnhealthyPodEvictionPolicyType) string {
|
||||
if unhealthyPodEvictionPolicy == nil {
|
||||
return "nil"
|
||||
}
|
||||
return string(*unhealthyPodEvictionPolicy)
|
||||
}
|
||||
|
||||
func hasUnhealthyPolicy(unhealthyPolicies []*policyv1.UnhealthyPodEvictionPolicyType, unhealthyPolicy *policyv1.UnhealthyPodEvictionPolicyType) bool {
|
||||
for _, p := range unhealthyPolicies {
|
||||
if reflect.DeepEqual(unhealthyPolicy, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func errToString(err error) string {
|
||||
result := ""
|
||||
if err != nil {
|
||||
result = err.Error()
|
||||
if statusErr, ok := err.(*apierrors.StatusError); ok {
|
||||
result += fmt.Sprintf(": %v", statusErr.ErrStatus.Reason)
|
||||
if statusErr.ErrStatus.Details != nil {
|
||||
for _, cause := range statusErr.ErrStatus.Details.Causes {
|
||||
if !strings.HasSuffix(err.Error(), cause.Message) {
|
||||
result += fmt.Sprintf(": %v", cause.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -26,9 +26,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/policy/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
@ -68,6 +70,8 @@ func (podDisruptionBudgetStrategy) PrepareForCreate(ctx context.Context, obj run
|
||||
podDisruptionBudget.Status = policy.PodDisruptionBudgetStatus{}
|
||||
|
||||
podDisruptionBudget.Generation = 1
|
||||
|
||||
dropDisabledFields(&podDisruptionBudget.Spec, nil)
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
@ -83,6 +87,8 @@ func (podDisruptionBudgetStrategy) PrepareForUpdate(ctx context.Context, obj, ol
|
||||
if !apiequality.Semantic.DeepEqual(oldPodDisruptionBudget.Spec, newPodDisruptionBudget.Spec) {
|
||||
newPodDisruptionBudget.Generation = oldPodDisruptionBudget.Generation + 1
|
||||
}
|
||||
|
||||
dropDisabledFields(&newPodDisruptionBudget.Spec, &oldPodDisruptionBudget.Spec)
|
||||
}
|
||||
|
||||
// Validate validates a new PodDisruptionBudget.
|
||||
@ -182,3 +188,23 @@ func hasInvalidLabelValueInLabelSelector(pdb *policy.PodDisruptionBudget) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// dropDisabledFields removes disabled fields from the pod disruption budget spec.
|
||||
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pod disruption budget spec.
|
||||
func dropDisabledFields(pdbSpec, oldPDBSpec *policy.PodDisruptionBudgetSpec) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PDBUnhealthyPodEvictionPolicy) {
|
||||
if !unhealthyPodEvictionPolicyInUse(oldPDBSpec) {
|
||||
pdbSpec.UnhealthyPodEvictionPolicy = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unhealthyPodEvictionPolicyInUse(oldPDBSpec *policy.PodDisruptionBudgetSpec) bool {
|
||||
if oldPDBSpec == nil {
|
||||
return false
|
||||
}
|
||||
if oldPDBSpec.UnhealthyPodEvictionPolicy != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -17,15 +17,176 @@ limitations under the License.
|
||||
package poddisruptionbudget
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
type unhealthyPodEvictionPolicyStrategyTestCase struct {
|
||||
name string
|
||||
enableUnhealthyPodEvictionPolicy bool
|
||||
disablePDBUnhealthyPodEvictionPolicyFeatureGateAfterCreate bool
|
||||
unhealthyPodEvictionPolicy *policy.UnhealthyPodEvictionPolicyType
|
||||
expectedUnhealthyPodEvictionPolicy *policy.UnhealthyPodEvictionPolicyType
|
||||
expectedValidationErr bool
|
||||
updateUnhealthyPodEvictionPolicy *policy.UnhealthyPodEvictionPolicyType
|
||||
expectedUpdateUnhealthyPodEvictionPolicy *policy.UnhealthyPodEvictionPolicyType
|
||||
expectedValidationUpdateErr bool
|
||||
}
|
||||
|
||||
func TestPodDisruptionBudgetStrategy(t *testing.T) {
|
||||
tests := map[string]bool{
|
||||
"PodDisruptionBudget strategy with PDBUnhealthyPodEvictionPolicy feature gate disabled": false,
|
||||
"PodDisruptionBudget strategy with PDBUnhealthyPodEvictionPolicy feature gate enabled": true,
|
||||
}
|
||||
|
||||
for name, enableUnhealthyPodEvictionPolicy := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, enableUnhealthyPodEvictionPolicy)()
|
||||
testPodDisruptionBudgetStrategy(t)
|
||||
})
|
||||
}
|
||||
|
||||
healthyPolicyTests := []unhealthyPodEvictionPolicyStrategyTestCase{
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate disabled should remove unhealthyPodEvictionPolicy",
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate disabled should remove invalid unhealthyPodEvictionPolicy",
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr("Invalid"),
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr("Invalid"),
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate enabled",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate enabled should respect unhealthyPodEvictionPolicy",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
expectedUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
expectedUpdateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate enabled should fail invalid unhealthyPodEvictionPolicy",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr("Invalid"),
|
||||
expectedValidationErr: true,
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with FeatureGate enabled should fail invalid unhealthyPodEvictionPolicy when updated",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr("Invalid"),
|
||||
expectedValidationUpdateErr: true,
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with unhealthyPodEvictionPolicy should be updated when feature gate is disabled",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
disablePDBUnhealthyPodEvictionPolicyFeatureGateAfterCreate: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
expectedUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
expectedUpdateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.IfHealthyBudget),
|
||||
},
|
||||
{
|
||||
name: "PodDisruptionBudget strategy with unhealthyPodEvictionPolicy should not be updated to invalid when feature gate is disabled",
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
disablePDBUnhealthyPodEvictionPolicyFeatureGateAfterCreate: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
expectedUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
updateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr("Invalid"),
|
||||
expectedValidationUpdateErr: true,
|
||||
expectedUpdateUnhealthyPodEvictionPolicy: unhealthyPolicyPtr(policy.AlwaysAllow),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range healthyPolicyTests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
testPodDisruptionBudgetStrategyWithUnhealthyPodEvictionPolicy(t, tc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testPodDisruptionBudgetStrategyWithUnhealthyPodEvictionPolicy(t *testing.T, tc unhealthyPodEvictionPolicyStrategyTestCase) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, tc.enableUnhealthyPodEvictionPolicy)()
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
if !Strategy.NamespaceScoped() {
|
||||
t.Errorf("PodDisruptionBudget must be namespace scoped")
|
||||
}
|
||||
if Strategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("PodDisruptionBudget should not allow create on update")
|
||||
}
|
||||
|
||||
validSelector := map[string]string{"a": "b"}
|
||||
minAvailable := intstr.FromInt(3)
|
||||
pdb := &policy.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||
Spec: policy.PodDisruptionBudgetSpec{
|
||||
MinAvailable: &minAvailable,
|
||||
Selector: &metav1.LabelSelector{MatchLabels: validSelector},
|
||||
UnhealthyPodEvictionPolicy: tc.unhealthyPodEvictionPolicy,
|
||||
},
|
||||
}
|
||||
|
||||
Strategy.PrepareForCreate(ctx, pdb)
|
||||
errs := Strategy.Validate(ctx, pdb)
|
||||
if len(errs) != 0 {
|
||||
if !tc.expectedValidationErr {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
}
|
||||
return // no point going further when we have invalid PDB
|
||||
}
|
||||
if len(errs) == 0 && tc.expectedValidationErr {
|
||||
t.Errorf("Expected error validating")
|
||||
}
|
||||
if !reflect.DeepEqual(pdb.Spec.UnhealthyPodEvictionPolicy, tc.expectedUnhealthyPodEvictionPolicy) {
|
||||
t.Errorf("Unexpected UnhealthyPodEvictionPolicy set: expected %v, got %v", tc.expectedUnhealthyPodEvictionPolicy, pdb.Spec.UnhealthyPodEvictionPolicy)
|
||||
}
|
||||
if tc.disablePDBUnhealthyPodEvictionPolicyFeatureGateAfterCreate {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, false)()
|
||||
}
|
||||
|
||||
newPdb := &policy.PodDisruptionBudget{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: pdb.Name, Namespace: pdb.Namespace},
|
||||
Spec: pdb.Spec,
|
||||
}
|
||||
if tc.updateUnhealthyPodEvictionPolicy != nil {
|
||||
newPdb.Spec.UnhealthyPodEvictionPolicy = tc.updateUnhealthyPodEvictionPolicy
|
||||
}
|
||||
|
||||
// Nothing in Spec changes: OK
|
||||
Strategy.PrepareForUpdate(ctx, newPdb, pdb)
|
||||
errs = Strategy.ValidateUpdate(ctx, newPdb, pdb)
|
||||
|
||||
if len(errs) != 0 {
|
||||
if !tc.expectedValidationUpdateErr {
|
||||
t.Errorf("Unexpected error updating PodDisruptionBudget %v", errs)
|
||||
}
|
||||
return // no point going further when we have invalid PDB
|
||||
}
|
||||
if len(errs) == 0 && tc.expectedValidationUpdateErr {
|
||||
t.Errorf("Expected error updating PodDisruptionBudget")
|
||||
}
|
||||
if !reflect.DeepEqual(newPdb.Spec.UnhealthyPodEvictionPolicy, tc.expectedUpdateUnhealthyPodEvictionPolicy) {
|
||||
t.Errorf("Unexpected UnhealthyPodEvictionPolicy set: expected %v, got %v", tc.expectedUpdateUnhealthyPodEvictionPolicy, newPdb.Spec.UnhealthyPodEvictionPolicy)
|
||||
}
|
||||
}
|
||||
|
||||
func testPodDisruptionBudgetStrategy(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
if !Strategy.NamespaceScoped() {
|
||||
t.Errorf("PodDisruptionBudget must be namespace scoped")
|
||||
@ -210,3 +371,86 @@ func TestPodDisruptionBudgetStatusValidationByApiVersion(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropDisabledFields(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
oldSpec *policy.PodDisruptionBudgetSpec
|
||||
newSpec *policy.PodDisruptionBudgetSpec
|
||||
expectNewSpec *policy.PodDisruptionBudgetSpec
|
||||
enableUnhealthyPodEvictionPolicy bool
|
||||
}{
|
||||
"disabled clears unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
oldSpec: nil,
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(nil),
|
||||
},
|
||||
"disabled does not allow updating unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(nil),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(nil),
|
||||
},
|
||||
"disabled preserves old unhealthyPodEvictionPolicy when both old and new have it": {
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
},
|
||||
"disabled allows updating unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.AlwaysAllow)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.AlwaysAllow)),
|
||||
},
|
||||
"enabled preserve unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
oldSpec: nil,
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
},
|
||||
"enabled allows updating unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(nil),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
},
|
||||
"enabled preserve unhealthyPodEvictionPolicy when both old and new have it": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
},
|
||||
"enabled updates unhealthyPodEvictionPolicy": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
oldSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.IfHealthyBudget)),
|
||||
newSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.AlwaysAllow)),
|
||||
expectNewSpec: specWithUnhealthyPodEvictionPolicy(unhealthyPolicyPtr(policy.AlwaysAllow)),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, tc.enableUnhealthyPodEvictionPolicy)()
|
||||
|
||||
oldSpecBefore := tc.oldSpec.DeepCopy()
|
||||
dropDisabledFields(tc.newSpec, tc.oldSpec)
|
||||
if !reflect.DeepEqual(tc.newSpec, tc.expectNewSpec) {
|
||||
t.Error(cmp.Diff(tc.newSpec, tc.expectNewSpec))
|
||||
}
|
||||
if !reflect.DeepEqual(tc.oldSpec, oldSpecBefore) {
|
||||
t.Error(cmp.Diff(tc.oldSpec, oldSpecBefore))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func unhealthyPolicyPtr(unhealthyPodEvictionPolicy policy.UnhealthyPodEvictionPolicyType) *policy.UnhealthyPodEvictionPolicyType {
|
||||
return &unhealthyPodEvictionPolicy
|
||||
}
|
||||
|
||||
func specWithUnhealthyPodEvictionPolicy(unhealthyPodEvictionPolicy *policy.UnhealthyPodEvictionPolicyType) *policy.PodDisruptionBudgetSpec {
|
||||
return &policy.PodDisruptionBudgetSpec{
|
||||
UnhealthyPodEvictionPolicy: unhealthyPodEvictionPolicy,
|
||||
}
|
||||
}
|
||||
|
150
staging/src/k8s.io/api/policy/v1/generated.pb.go
generated
150
staging/src/k8s.io/api/policy/v1/generated.pb.go
generated
@ -201,58 +201,61 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_2d50488813b2d18e = []byte{
|
||||
// 808 bytes of a gzipped FileDescriptorProto
|
||||
// 854 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x96, 0xcf, 0x8f, 0xdb, 0x44,
|
||||
0x14, 0xc7, 0xe3, 0xcd, 0x66, 0x59, 0xa6, 0x49, 0xb4, 0x0c, 0x0b, 0x2c, 0x39, 0x38, 0x28, 0xa7,
|
||||
0x82, 0xd4, 0x31, 0xdb, 0x22, 0xb4, 0xaa, 0x04, 0xa2, 0x6e, 0x56, 0x50, 0xd4, 0x25, 0xd5, 0x2c,
|
||||
0x08, 0x09, 0x81, 0xc4, 0xc4, 0x7e, 0xcd, 0x0e, 0xb1, 0x3d, 0xd6, 0xcc, 0x38, 0x34, 0x27, 0xf8,
|
||||
0x13, 0xf8, 0x17, 0xf8, 0x53, 0x38, 0xb1, 0x27, 0xd4, 0x63, 0xc5, 0x21, 0x62, 0xcd, 0x3f, 0x82,
|
||||
0x3c, 0x76, 0x7e, 0x38, 0xf1, 0xaa, 0x59, 0x0e, 0xbd, 0x79, 0xde, 0x7b, 0xdf, 0xcf, 0x9b, 0xf7,
|
||||
0xe6, 0xcd, 0xc8, 0xe8, 0x93, 0xf1, 0x89, 0x22, 0x5c, 0x38, 0xe3, 0x64, 0x08, 0x32, 0x02, 0x0d,
|
||||
0xca, 0x99, 0x40, 0xe4, 0x0b, 0xe9, 0x14, 0x0e, 0x16, 0x73, 0x27, 0x16, 0x01, 0xf7, 0xa6, 0xce,
|
||||
0xe4, 0xd8, 0x19, 0x41, 0x04, 0x92, 0x69, 0xf0, 0x49, 0x2c, 0x85, 0x16, 0xf8, 0x30, 0x8f, 0x22,
|
||||
0x2c, 0xe6, 0x24, 0x8f, 0x22, 0x93, 0xe3, 0xce, 0x9d, 0x11, 0xd7, 0x17, 0xc9, 0x90, 0x78, 0x22,
|
||||
0x74, 0x46, 0x62, 0x24, 0x1c, 0x13, 0x3c, 0x4c, 0x9e, 0x9a, 0x95, 0x59, 0x98, 0xaf, 0x1c, 0xd2,
|
||||
0xf9, 0x68, 0x99, 0x2a, 0x64, 0xde, 0x05, 0x8f, 0x40, 0x4e, 0x9d, 0x78, 0x3c, 0xca, 0x0c, 0xca,
|
||||
0x09, 0x41, 0xb3, 0x8a, 0xd4, 0x1d, 0xe7, 0x3a, 0x95, 0x4c, 0x22, 0xcd, 0x43, 0xd8, 0x10, 0x7c,
|
||||
0xfc, 0x32, 0x81, 0xf2, 0x2e, 0x20, 0x64, 0x1b, 0xba, 0x7b, 0xd7, 0xe9, 0x12, 0xcd, 0x03, 0x87,
|
||||
0x47, 0x5a, 0x69, 0xb9, 0x2e, 0xea, 0xfd, 0x6d, 0xa1, 0xfd, 0xd3, 0x09, 0xf7, 0x34, 0x17, 0x11,
|
||||
0xfe, 0x11, 0xed, 0x67, 0x55, 0xf8, 0x4c, 0xb3, 0x23, 0xeb, 0x3d, 0xeb, 0xf6, 0xad, 0xbb, 0x1f,
|
||||
0x92, 0x65, 0xe3, 0x16, 0x50, 0x12, 0x8f, 0x47, 0x99, 0x41, 0x91, 0x2c, 0x9a, 0x4c, 0x8e, 0xc9,
|
||||
0x60, 0xf8, 0x13, 0x78, 0xfa, 0x0c, 0x34, 0x73, 0xf1, 0xe5, 0xac, 0x5b, 0x4b, 0x67, 0x5d, 0xb4,
|
||||
0xb4, 0xd1, 0x05, 0x15, 0x07, 0xa8, 0xe5, 0x43, 0x00, 0x1a, 0x06, 0x71, 0x96, 0x51, 0x1d, 0xed,
|
||||
0x98, 0x34, 0xf7, 0xb6, 0x4b, 0xd3, 0x5f, 0x95, 0xba, 0x6f, 0xa4, 0xb3, 0x6e, 0xab, 0x64, 0xa2,
|
||||
0x65, 0x78, 0xef, 0xf7, 0x1d, 0xf4, 0xe6, 0x13, 0xe1, 0xf7, 0xb9, 0x92, 0x89, 0x31, 0xb9, 0x89,
|
||||
0x3f, 0x02, 0xfd, 0x0a, 0xea, 0x1c, 0xa0, 0x5d, 0x15, 0x83, 0x57, 0x94, 0x77, 0x87, 0x54, 0x8d,
|
||||
0x1f, 0xa9, 0xd8, 0xda, 0x79, 0x0c, 0x9e, 0xdb, 0x2c, 0xd0, 0xbb, 0xd9, 0x8a, 0x1a, 0x10, 0xfe,
|
||||
0x16, 0xed, 0x29, 0xcd, 0x74, 0xa2, 0x8e, 0xea, 0x06, 0xe9, 0x6c, 0x8f, 0x34, 0x32, 0xb7, 0x5d,
|
||||
0x40, 0xf7, 0xf2, 0x35, 0x2d, 0x70, 0xbd, 0x3f, 0x2d, 0xf4, 0x4e, 0x85, 0xea, 0x31, 0x57, 0x1a,
|
||||
0x7f, 0xbf, 0xd1, 0x27, 0xb2, 0x5d, 0x9f, 0x32, 0xb5, 0xe9, 0xd2, 0x41, 0x91, 0x75, 0x7f, 0x6e,
|
||||
0x59, 0xe9, 0xd1, 0x57, 0xa8, 0xc1, 0x35, 0x84, 0xd9, 0x0c, 0xd4, 0x6f, 0xdf, 0xba, 0xfb, 0xfe,
|
||||
0xd6, 0x15, 0xb9, 0xad, 0x82, 0xda, 0x78, 0x94, 0xe9, 0x69, 0x8e, 0xe9, 0xfd, 0xb5, 0x53, 0x59,
|
||||
0x49, 0xd6, 0x44, 0xfc, 0x14, 0x35, 0x43, 0x1e, 0x3d, 0x98, 0x30, 0x1e, 0xb0, 0x61, 0x00, 0x2f,
|
||||
0x3d, 0xf5, 0xec, 0xca, 0x90, 0xfc, 0xca, 0x90, 0x47, 0x91, 0x1e, 0xc8, 0x73, 0x2d, 0x79, 0x34,
|
||||
0x72, 0x0f, 0xd2, 0x59, 0xb7, 0x79, 0xb6, 0x42, 0xa2, 0x25, 0x2e, 0xfe, 0x01, 0xed, 0x2b, 0x08,
|
||||
0xc0, 0xd3, 0x42, 0xde, 0x6c, 0xb4, 0x1f, 0xb3, 0x21, 0x04, 0xe7, 0x85, 0xd4, 0x6d, 0x66, 0x2d,
|
||||
0x9b, 0xaf, 0xe8, 0x02, 0x89, 0x03, 0xd4, 0x0e, 0xd9, 0xb3, 0x6f, 0x22, 0xb6, 0x28, 0xa4, 0xfe,
|
||||
0x3f, 0x0b, 0xc1, 0xe9, 0xac, 0xdb, 0x3e, 0x2b, 0xb1, 0xe8, 0x1a, 0xbb, 0xf7, 0x47, 0x03, 0xbd,
|
||||
0x7b, 0xed, 0x40, 0xe1, 0x2f, 0x11, 0x16, 0x43, 0x05, 0x72, 0x02, 0xfe, 0xe7, 0xf9, 0xa3, 0xc2,
|
||||
0x45, 0x64, 0x1a, 0x5b, 0x77, 0x3b, 0xc5, 0x01, 0xe1, 0xc1, 0x46, 0x04, 0xad, 0x50, 0xe1, 0x5f,
|
||||
0x50, 0xcb, 0xcf, 0xb3, 0x80, 0xff, 0x44, 0xf8, 0xf3, 0x91, 0x70, 0x6f, 0x38, 0xe4, 0xa4, 0xbf,
|
||||
0x0a, 0x39, 0x8d, 0xb4, 0x9c, 0xba, 0x6f, 0x15, 0x5b, 0x69, 0x95, 0x7c, 0xb4, 0x9c, 0x2f, 0x2b,
|
||||
0xc6, 0x5f, 0x20, 0xd5, 0x83, 0x20, 0x10, 0x3f, 0x83, 0x6f, 0x9a, 0xdb, 0x58, 0x16, 0xd3, 0xdf,
|
||||
0x88, 0xa0, 0x15, 0x2a, 0xfc, 0x29, 0x6a, 0x7b, 0x89, 0x94, 0x10, 0xe9, 0x2f, 0x80, 0x05, 0xfa,
|
||||
0x62, 0x7a, 0xb4, 0x6b, 0x38, 0x6f, 0x17, 0x9c, 0xf6, 0xc3, 0x92, 0x97, 0xae, 0x45, 0x67, 0x7a,
|
||||
0x1f, 0x14, 0x97, 0xe0, 0xcf, 0xf5, 0x8d, 0xb2, 0xbe, 0x5f, 0xf2, 0xd2, 0xb5, 0x68, 0x7c, 0x82,
|
||||
0x9a, 0xf0, 0x2c, 0x06, 0x6f, 0xde, 0xcb, 0x3d, 0xa3, 0x3e, 0x2c, 0xd4, 0xcd, 0xd3, 0x15, 0x1f,
|
||||
0x2d, 0x45, 0x62, 0x0f, 0x21, 0x4f, 0x44, 0x3e, 0xcf, 0x9f, 0xe6, 0xd7, 0xcc, 0x19, 0x38, 0xdb,
|
||||
0xcd, 0xef, 0xc3, 0xb9, 0x6e, 0xf9, 0x30, 0x2e, 0x4c, 0x8a, 0xae, 0x60, 0x3b, 0x01, 0xc2, 0x9b,
|
||||
0xc7, 0x84, 0x0f, 0x50, 0x7d, 0x0c, 0x53, 0x33, 0x3e, 0xaf, 0xd3, 0xec, 0x13, 0x7f, 0x86, 0x1a,
|
||||
0x13, 0x16, 0x24, 0x50, 0xdc, 0xa3, 0x0f, 0xb6, 0xdb, 0xc7, 0xd7, 0x3c, 0x04, 0x9a, 0x0b, 0xef,
|
||||
0xef, 0x9c, 0x58, 0xee, 0xfd, 0xcb, 0x2b, 0xbb, 0xf6, 0xfc, 0xca, 0xae, 0xbd, 0xb8, 0xb2, 0x6b,
|
||||
0xbf, 0xa6, 0xb6, 0x75, 0x99, 0xda, 0xd6, 0xf3, 0xd4, 0xb6, 0x5e, 0xa4, 0xb6, 0xf5, 0x4f, 0x6a,
|
||||
0x5b, 0xbf, 0xfd, 0x6b, 0xd7, 0xbe, 0x3b, 0xac, 0xfa, 0x89, 0xf8, 0x2f, 0x00, 0x00, 0xff, 0xff,
|
||||
0x8d, 0x9b, 0x69, 0xee, 0x74, 0x08, 0x00, 0x00,
|
||||
0x14, 0xc7, 0xe3, 0xcd, 0x66, 0xd9, 0x4e, 0x93, 0x68, 0x19, 0x16, 0x58, 0x72, 0x70, 0xaa, 0x9c,
|
||||
0x16, 0xa4, 0x8e, 0xd9, 0x16, 0xa1, 0x55, 0x25, 0x50, 0xeb, 0x66, 0x05, 0x45, 0x5d, 0xb2, 0x9a,
|
||||
0x6d, 0x85, 0x84, 0x40, 0x62, 0x62, 0xbf, 0x26, 0x43, 0x6c, 0x8f, 0xe5, 0x19, 0x87, 0xe6, 0x44,
|
||||
0xff, 0x04, 0xfe, 0x05, 0xfe, 0x14, 0x4e, 0xec, 0xb1, 0xdc, 0x2a, 0x0e, 0x11, 0x6b, 0xfe, 0x0b,
|
||||
0x4e, 0xc8, 0x63, 0xe7, 0x87, 0x37, 0x0e, 0xcd, 0x72, 0xe8, 0xcd, 0xf3, 0xde, 0xfb, 0x7e, 0x9e,
|
||||
0xdf, 0x8f, 0x71, 0x82, 0x3e, 0x1b, 0x1d, 0x4b, 0xc2, 0x85, 0x35, 0x8a, 0xfb, 0x10, 0x05, 0xa0,
|
||||
0x40, 0x5a, 0x63, 0x08, 0x5c, 0x11, 0x59, 0xb9, 0x83, 0x85, 0xdc, 0x0a, 0x85, 0xc7, 0x9d, 0x89,
|
||||
0x35, 0x3e, 0xb2, 0x06, 0x10, 0x40, 0xc4, 0x14, 0xb8, 0x24, 0x8c, 0x84, 0x12, 0x78, 0x3f, 0x8b,
|
||||
0x22, 0x2c, 0xe4, 0x24, 0x8b, 0x22, 0xe3, 0xa3, 0xd6, 0xed, 0x01, 0x57, 0xc3, 0xb8, 0x4f, 0x1c,
|
||||
0xe1, 0x5b, 0x03, 0x31, 0x10, 0x96, 0x0e, 0xee, 0xc7, 0xcf, 0xf4, 0x49, 0x1f, 0xf4, 0x53, 0x06,
|
||||
0x69, 0x7d, 0xb2, 0x48, 0xe5, 0x33, 0x67, 0xc8, 0x03, 0x88, 0x26, 0x56, 0x38, 0x1a, 0xa4, 0x06,
|
||||
0x69, 0xf9, 0xa0, 0x58, 0x49, 0xea, 0x96, 0xb5, 0x4e, 0x15, 0xc5, 0x81, 0xe2, 0x3e, 0xac, 0x08,
|
||||
0x3e, 0x7d, 0x9d, 0x40, 0x3a, 0x43, 0xf0, 0xd9, 0x8a, 0xee, 0xee, 0x3a, 0x5d, 0xac, 0xb8, 0x67,
|
||||
0xf1, 0x40, 0x49, 0x15, 0x5d, 0x15, 0x75, 0xfe, 0x34, 0xd0, 0xee, 0xc9, 0x98, 0x3b, 0x8a, 0x8b,
|
||||
0x00, 0xff, 0x80, 0x76, 0xd3, 0x2a, 0x5c, 0xa6, 0xd8, 0x81, 0x71, 0xcb, 0x38, 0xbc, 0x79, 0xe7,
|
||||
0x63, 0xb2, 0x68, 0xdc, 0x1c, 0x4a, 0xc2, 0xd1, 0x20, 0x35, 0x48, 0x92, 0x46, 0x93, 0xf1, 0x11,
|
||||
0xe9, 0xf5, 0x7f, 0x04, 0x47, 0x9d, 0x82, 0x62, 0x36, 0xbe, 0x98, 0xb6, 0x2b, 0xc9, 0xb4, 0x8d,
|
||||
0x16, 0x36, 0x3a, 0xa7, 0x62, 0x0f, 0x35, 0x5c, 0xf0, 0x40, 0x41, 0x2f, 0x4c, 0x33, 0xca, 0x83,
|
||||
0x2d, 0x9d, 0xe6, 0xee, 0x66, 0x69, 0xba, 0xcb, 0x52, 0xfb, 0xed, 0x64, 0xda, 0x6e, 0x14, 0x4c,
|
||||
0xb4, 0x08, 0xef, 0xfc, 0xba, 0x85, 0xde, 0x39, 0x13, 0x6e, 0x97, 0xcb, 0x28, 0xd6, 0x26, 0x3b,
|
||||
0x76, 0x07, 0xa0, 0xde, 0x40, 0x9d, 0x3d, 0xb4, 0x2d, 0x43, 0x70, 0xf2, 0xf2, 0x6e, 0x93, 0xb2,
|
||||
0xf5, 0x23, 0x25, 0xaf, 0x76, 0x1e, 0x82, 0x63, 0xd7, 0x73, 0xf4, 0x76, 0x7a, 0xa2, 0x1a, 0x84,
|
||||
0xbf, 0x41, 0x3b, 0x52, 0x31, 0x15, 0xcb, 0x83, 0xaa, 0x46, 0x5a, 0x9b, 0x23, 0xb5, 0xcc, 0x6e,
|
||||
0xe6, 0xd0, 0x9d, 0xec, 0x4c, 0x73, 0x5c, 0xe7, 0x77, 0x03, 0xbd, 0x5f, 0xa2, 0x7a, 0xcc, 0xa5,
|
||||
0xc2, 0xdf, 0xad, 0xf4, 0x89, 0x6c, 0xd6, 0xa7, 0x54, 0xad, 0xbb, 0xb4, 0x97, 0x67, 0xdd, 0x9d,
|
||||
0x59, 0x96, 0x7a, 0xf4, 0x35, 0xaa, 0x71, 0x05, 0x7e, 0xba, 0x03, 0xd5, 0xc3, 0x9b, 0x77, 0x3e,
|
||||
0xdc, 0xb8, 0x22, 0xbb, 0x91, 0x53, 0x6b, 0x8f, 0x52, 0x3d, 0xcd, 0x30, 0x9d, 0x3f, 0xaa, 0xa5,
|
||||
0x95, 0xa4, 0x4d, 0xc4, 0xcf, 0x50, 0xdd, 0xe7, 0xc1, 0x83, 0x31, 0xe3, 0x1e, 0xeb, 0x7b, 0xf0,
|
||||
0xda, 0xa9, 0xa7, 0x57, 0x86, 0x64, 0x57, 0x86, 0x3c, 0x0a, 0x54, 0x2f, 0x3a, 0x57, 0x11, 0x0f,
|
||||
0x06, 0xf6, 0x5e, 0x32, 0x6d, 0xd7, 0x4f, 0x97, 0x48, 0xb4, 0xc0, 0xc5, 0xdf, 0xa3, 0x5d, 0x09,
|
||||
0x1e, 0x38, 0x4a, 0x44, 0xd7, 0x5b, 0xed, 0xc7, 0xac, 0x0f, 0xde, 0x79, 0x2e, 0xb5, 0xeb, 0x69,
|
||||
0xcb, 0x66, 0x27, 0x3a, 0x47, 0x62, 0x0f, 0x35, 0x7d, 0xf6, 0xfc, 0x69, 0xc0, 0xe6, 0x85, 0x54,
|
||||
0xff, 0x67, 0x21, 0x38, 0x99, 0xb6, 0x9b, 0xa7, 0x05, 0x16, 0xbd, 0xc2, 0xc6, 0x2f, 0x0c, 0xd4,
|
||||
0x8a, 0x83, 0x21, 0x30, 0x4f, 0x0d, 0x27, 0x67, 0xc2, 0x9d, 0x7d, 0x27, 0xce, 0xf4, 0x70, 0x0e,
|
||||
0xb6, 0x6f, 0x19, 0x87, 0x37, 0xec, 0xfb, 0xc9, 0xb4, 0xdd, 0x7a, 0xba, 0x36, 0xea, 0x9f, 0x69,
|
||||
0xdb, 0x5c, 0xef, 0x7d, 0x32, 0x09, 0x81, 0xfe, 0x47, 0x8e, 0xce, 0x6f, 0x35, 0xf4, 0xc1, 0xda,
|
||||
0x9d, 0xc6, 0x5f, 0x21, 0x2c, 0xfa, 0x12, 0xa2, 0x31, 0xb8, 0x5f, 0x64, 0xdf, 0x35, 0x2e, 0x02,
|
||||
0x3d, 0xdb, 0xaa, 0xdd, 0xca, 0x77, 0x04, 0xf7, 0x56, 0x22, 0x68, 0x89, 0x0a, 0xff, 0x8c, 0x1a,
|
||||
0x6e, 0x96, 0x05, 0xdc, 0x33, 0xe1, 0xce, 0xb6, 0xd2, 0xbe, 0xe6, 0x3d, 0x23, 0xdd, 0x65, 0xc8,
|
||||
0x49, 0xa0, 0xa2, 0x89, 0xfd, 0x6e, 0xfe, 0x2a, 0x8d, 0x82, 0x8f, 0x16, 0xf3, 0xa5, 0xc5, 0xb8,
|
||||
0x73, 0xa4, 0x7c, 0xe0, 0x79, 0xe2, 0x27, 0x70, 0xf5, 0x7c, 0x6b, 0x8b, 0x62, 0xba, 0x2b, 0x11,
|
||||
0xb4, 0x44, 0x85, 0x3f, 0x47, 0x4d, 0x27, 0x8e, 0x22, 0x08, 0xd4, 0x97, 0x59, 0x67, 0xf5, 0xb0,
|
||||
0x6a, 0xf6, 0x7b, 0x39, 0xa7, 0xf9, 0xb0, 0xe0, 0xa5, 0x57, 0xa2, 0x53, 0xbd, 0x0b, 0x92, 0x47,
|
||||
0xe0, 0xce, 0xf4, 0xb5, 0xa2, 0xbe, 0x5b, 0xf0, 0xd2, 0x2b, 0xd1, 0xf8, 0x18, 0xd5, 0xe1, 0x79,
|
||||
0x08, 0xce, 0xac, 0x97, 0x3b, 0x5a, 0xbd, 0x9f, 0xab, 0xeb, 0x27, 0x4b, 0x3e, 0x5a, 0x88, 0xc4,
|
||||
0x0e, 0x42, 0x8e, 0x08, 0x5c, 0x9e, 0xfd, 0x3a, 0xbc, 0xa5, 0x67, 0x60, 0x6d, 0x76, 0x85, 0x1e,
|
||||
0xce, 0x74, 0x8b, 0x6f, 0xf3, 0xdc, 0x24, 0xe9, 0x12, 0xb6, 0xe5, 0x21, 0xbc, 0x3a, 0x26, 0xbc,
|
||||
0x87, 0xaa, 0x23, 0x98, 0xe8, 0xf5, 0xb9, 0x41, 0xd3, 0x47, 0x7c, 0x1f, 0xd5, 0xc6, 0xcc, 0x8b,
|
||||
0x21, 0xbf, 0xca, 0x1f, 0x6d, 0xf6, 0x1e, 0x4f, 0xb8, 0x0f, 0x34, 0x13, 0xde, 0xdb, 0x3a, 0x36,
|
||||
0xec, 0x7b, 0x17, 0x97, 0x66, 0xe5, 0xe5, 0xa5, 0x59, 0x79, 0x75, 0x69, 0x56, 0x5e, 0x24, 0xa6,
|
||||
0x71, 0x91, 0x98, 0xc6, 0xcb, 0xc4, 0x34, 0x5e, 0x25, 0xa6, 0xf1, 0x57, 0x62, 0x1a, 0xbf, 0xfc,
|
||||
0x6d, 0x56, 0xbe, 0xdd, 0x2f, 0xfb, 0x1f, 0xf3, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0xd7,
|
||||
0x99, 0xdb, 0xf7, 0x08, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Eviction) Marshal() (dAtA []byte, err error) {
|
||||
@ -420,6 +423,13 @@ func (m *PodDisruptionBudgetSpec) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.UnhealthyPodEvictionPolicy != nil {
|
||||
i -= len(*m.UnhealthyPodEvictionPolicy)
|
||||
copy(dAtA[i:], *m.UnhealthyPodEvictionPolicy)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.UnhealthyPodEvictionPolicy)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.MaxUnavailable != nil {
|
||||
{
|
||||
size, err := m.MaxUnavailable.MarshalToSizedBuffer(dAtA[:i])
|
||||
@ -616,6 +626,10 @@ func (m *PodDisruptionBudgetSpec) Size() (n int) {
|
||||
l = m.MaxUnavailable.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
if m.UnhealthyPodEvictionPolicy != nil {
|
||||
l = len(*m.UnhealthyPodEvictionPolicy)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -701,6 +715,7 @@ func (this *PodDisruptionBudgetSpec) String() string {
|
||||
`MinAvailable:` + strings.Replace(fmt.Sprintf("%v", this.MinAvailable), "IntOrString", "intstr.IntOrString", 1) + `,`,
|
||||
`Selector:` + strings.Replace(fmt.Sprintf("%v", this.Selector), "LabelSelector", "v1.LabelSelector", 1) + `,`,
|
||||
`MaxUnavailable:` + strings.Replace(fmt.Sprintf("%v", this.MaxUnavailable), "IntOrString", "intstr.IntOrString", 1) + `,`,
|
||||
`UnhealthyPodEvictionPolicy:` + valueToStringGenerated(this.UnhealthyPodEvictionPolicy) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@ -1266,6 +1281,39 @@ func (m *PodDisruptionBudgetSpec) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field UnhealthyPodEvictionPolicy", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := UnhealthyPodEvictionPolicyType(dAtA[iNdEx:postIndex])
|
||||
m.UnhealthyPodEvictionPolicy = &s
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
@ -92,6 +92,34 @@ message PodDisruptionBudgetSpec {
|
||||
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 3;
|
||||
|
||||
// UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction. Current implementation considers healthy pods,
|
||||
// as pods that have status.conditions item with type="Ready",status="True".
|
||||
//
|
||||
// Valid policies are IfHealthyBudget and AlwaysAllow.
|
||||
// If no policy is specified, the default behavior will be used,
|
||||
// which corresponds to the IfHealthyBudget policy.
|
||||
//
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// Additional policies may be added in the future.
|
||||
// Clients making eviction decisions should disallow eviction of unhealthy pods
|
||||
// if they encounter an unrecognized policy in this field.
|
||||
//
|
||||
// This field is alpha-level. The eviction API uses this field when
|
||||
// the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).
|
||||
// +optional
|
||||
optional string unhealthyPodEvictionPolicy = 4;
|
||||
}
|
||||
|
||||
// PodDisruptionBudgetStatus represents information about the status of a
|
||||
|
@ -47,8 +47,56 @@ type PodDisruptionBudgetSpec struct {
|
||||
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
|
||||
// +optional
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,3,opt,name=maxUnavailable"`
|
||||
|
||||
// UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction. Current implementation considers healthy pods,
|
||||
// as pods that have status.conditions item with type="Ready",status="True".
|
||||
//
|
||||
// Valid policies are IfHealthyBudget and AlwaysAllow.
|
||||
// If no policy is specified, the default behavior will be used,
|
||||
// which corresponds to the IfHealthyBudget policy.
|
||||
//
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// Additional policies may be added in the future.
|
||||
// Clients making eviction decisions should disallow eviction of unhealthy pods
|
||||
// if they encounter an unrecognized policy in this field.
|
||||
//
|
||||
// This field is alpha-level. The eviction API uses this field when
|
||||
// the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).
|
||||
// +optional
|
||||
UnhealthyPodEvictionPolicy *UnhealthyPodEvictionPolicyType `json:"unhealthyPodEvictionPolicy,omitempty" protobuf:"bytes,4,opt,name=unhealthyPodEvictionPolicy"`
|
||||
}
|
||||
|
||||
// UnhealthyPodEvictionPolicyType defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction.
|
||||
// +enum
|
||||
type UnhealthyPodEvictionPolicyType string
|
||||
|
||||
const (
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
IfHealthyBudget UnhealthyPodEvictionPolicyType = "IfHealthyBudget"
|
||||
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
AlwaysAllow UnhealthyPodEvictionPolicyType = "AlwaysAllow"
|
||||
)
|
||||
|
||||
// PodDisruptionBudgetStatus represents information about the status of a
|
||||
// PodDisruptionBudget. Status may trail the actual state of a system.
|
||||
type PodDisruptionBudgetStatus struct {
|
||||
|
@ -63,6 +63,7 @@ var map_PodDisruptionBudgetSpec = map[string]string{
|
||||
"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\".",
|
||||
"unhealthyPodEvictionPolicy": "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
}
|
||||
|
||||
func (PodDisruptionBudgetSpec) SwaggerDoc() map[string]string {
|
||||
|
@ -137,6 +137,11 @@ func (in *PodDisruptionBudgetSpec) DeepCopyInto(out *PodDisruptionBudgetSpec) {
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
if in.UnhealthyPodEvictionPolicy != nil {
|
||||
in, out := &in.UnhealthyPodEvictionPolicy, &out.UnhealthyPodEvictionPolicy
|
||||
*out = new(UnhealthyPodEvictionPolicyType)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
287
staging/src/k8s.io/api/policy/v1beta1/generated.pb.go
generated
287
staging/src/k8s.io/api/policy/v1beta1/generated.pb.go
generated
@ -609,127 +609,129 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_014060e454a820dc = []byte{
|
||||
// 1907 bytes of a gzipped FileDescriptorProto
|
||||
// 1946 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0x5b, 0x73, 0xdb, 0xc6,
|
||||
0xf5, 0x17, 0x4c, 0x5d, 0xa8, 0xd5, 0xc5, 0xe2, 0xea, 0x62, 0x48, 0xf9, 0x87, 0x70, 0x90, 0x99,
|
||||
0xff, 0xb8, 0x69, 0x0a, 0xc6, 0xb2, 0xe3, 0x7a, 0x9a, 0x5e, 0x22, 0x88, 0x92, 0xad, 0x8c, 0x65,
|
||||
0xb1, 0x4b, 0x3b, 0xd3, 0x76, 0xdc, 0x4e, 0x97, 0xc0, 0x8a, 0x42, 0x04, 0x02, 0x28, 0x76, 0xc1,
|
||||
0x88, 0x6f, 0x7d, 0xe8, 0x43, 0x1f, 0xfb, 0x05, 0x32, 0xfd, 0x00, 0x9d, 0x3e, 0xf5, 0x43, 0xd4,
|
||||
0x99, 0xe9, 0x64, 0xf2, 0x98, 0xe9, 0x03, 0xa7, 0x66, 0xbf, 0x85, 0x9f, 0x3a, 0x58, 0x2e, 0x40,
|
||||
0x5c, 0x49, 0x3b, 0x33, 0xf6, 0x1b, 0xb1, 0xe7, 0xf7, 0xfb, 0x9d, 0xdd, 0xb3, 0x67, 0xcf, 0x5e,
|
||||
0x08, 0xf4, 0xcb, 0xfb, 0x54, 0xb3, 0xdc, 0xc6, 0x65, 0xd0, 0x21, 0xbe, 0x43, 0x18, 0xa1, 0x8d,
|
||||
0x3e, 0x71, 0x4c, 0xd7, 0x6f, 0x08, 0x03, 0xf6, 0xac, 0x86, 0xe7, 0xda, 0x96, 0x31, 0x68, 0xf4,
|
||||
0x6f, 0x77, 0x08, 0xc3, 0xb7, 0x1b, 0x5d, 0xe2, 0x10, 0x1f, 0x33, 0x62, 0x6a, 0x9e, 0xef, 0x32,
|
||||
0x17, 0xee, 0x8e, 0xa1, 0x1a, 0xf6, 0x2c, 0x6d, 0x0c, 0xd5, 0x04, 0x74, 0xef, 0x47, 0x5d, 0x8b,
|
||||
0x5d, 0x04, 0x1d, 0xcd, 0x70, 0x7b, 0x8d, 0xae, 0xdb, 0x75, 0x1b, 0x9c, 0xd1, 0x09, 0xce, 0xf9,
|
||||
0x17, 0xff, 0xe0, 0xbf, 0xc6, 0x4a, 0x7b, 0x6a, 0xc2, 0xa9, 0xe1, 0xfa, 0xa4, 0xd1, 0xcf, 0x79,
|
||||
0xdb, 0xbb, 0x3b, 0xc1, 0xf4, 0xb0, 0x71, 0x61, 0x39, 0xc4, 0x1f, 0x34, 0xbc, 0xcb, 0x6e, 0xd8,
|
||||
0x40, 0x1b, 0x3d, 0xc2, 0x70, 0x11, 0xab, 0x51, 0xc6, 0xf2, 0x03, 0x87, 0x59, 0x3d, 0x92, 0x23,
|
||||
0xdc, 0x9b, 0x45, 0xa0, 0xc6, 0x05, 0xe9, 0xe1, 0x1c, 0xef, 0x4e, 0x19, 0x2f, 0x60, 0x96, 0xdd,
|
||||
0xb0, 0x1c, 0x46, 0x99, 0x9f, 0x25, 0xa9, 0x77, 0xc1, 0xc6, 0x81, 0x6d, 0xbb, 0x5f, 0x12, 0xf3,
|
||||
0xb0, 0x7d, 0xd2, 0xf4, 0xad, 0x3e, 0xf1, 0xe1, 0x4d, 0x30, 0xef, 0xe0, 0x1e, 0x91, 0xa5, 0x9b,
|
||||
0xd2, 0xad, 0x65, 0x7d, 0xf5, 0xf9, 0x50, 0x99, 0x1b, 0x0d, 0x95, 0xf9, 0xc7, 0xb8, 0x47, 0x10,
|
||||
0xb7, 0xa8, 0x9f, 0x80, 0x9a, 0x60, 0x1d, 0xdb, 0xe4, 0xea, 0x73, 0xd7, 0x0e, 0x7a, 0x04, 0xfe,
|
||||
0x3f, 0x58, 0x34, 0xb9, 0x80, 0x20, 0xae, 0x0b, 0xe2, 0xe2, 0x58, 0x16, 0x09, 0xab, 0x4a, 0xc1,
|
||||
0x75, 0x41, 0x7e, 0xe8, 0x52, 0xd6, 0xc2, 0xec, 0x02, 0xee, 0x03, 0xe0, 0x61, 0x76, 0xd1, 0xf2,
|
||||
0xc9, 0xb9, 0x75, 0x25, 0xe8, 0x50, 0xd0, 0x41, 0x2b, 0xb6, 0xa0, 0x04, 0x0a, 0x7e, 0x08, 0xaa,
|
||||
0x3e, 0xc1, 0xe6, 0x99, 0x63, 0x0f, 0xe4, 0x6b, 0x37, 0xa5, 0x5b, 0x55, 0x7d, 0x43, 0x30, 0xaa,
|
||||
0x48, 0xb4, 0xa3, 0x18, 0xa1, 0xfe, 0x5b, 0x02, 0xd5, 0xa3, 0xbe, 0x65, 0x30, 0xcb, 0x75, 0xe0,
|
||||
0xef, 0x41, 0x35, 0x9c, 0x2d, 0x13, 0x33, 0xcc, 0x9d, 0xad, 0xec, 0x7f, 0xa4, 0x4d, 0x32, 0x29,
|
||||
0x0e, 0x9e, 0xe6, 0x5d, 0x76, 0xc3, 0x06, 0xaa, 0x85, 0x68, 0xad, 0x7f, 0x5b, 0x3b, 0xeb, 0x7c,
|
||||
0x41, 0x0c, 0x76, 0x4a, 0x18, 0x9e, 0x74, 0x6f, 0xd2, 0x86, 0x62, 0x55, 0x68, 0x83, 0x35, 0x93,
|
||||
0xd8, 0x84, 0x91, 0x33, 0x2f, 0xf4, 0x48, 0x79, 0x0f, 0x57, 0xf6, 0xef, 0xbc, 0x9a, 0x9b, 0x66,
|
||||
0x92, 0xaa, 0xd7, 0x46, 0x43, 0x65, 0x2d, 0xd5, 0x84, 0xd2, 0xe2, 0xea, 0x57, 0x12, 0xd8, 0x39,
|
||||
0x6e, 0x3f, 0xf0, 0xdd, 0xc0, 0x6b, 0xb3, 0x70, 0x76, 0xbb, 0x03, 0x61, 0x82, 0x3f, 0x06, 0xf3,
|
||||
0x7e, 0x60, 0x47, 0x73, 0xf9, 0x7e, 0x34, 0x97, 0x28, 0xb0, 0xc9, 0xcb, 0xa1, 0xb2, 0x99, 0x61,
|
||||
0x3d, 0x19, 0x78, 0x04, 0x71, 0x02, 0xfc, 0x0c, 0x2c, 0xfa, 0xd8, 0xe9, 0x92, 0xb0, 0xeb, 0x95,
|
||||
0x5b, 0x2b, 0xfb, 0xaa, 0x56, 0xba, 0xd6, 0xb4, 0x93, 0x26, 0x0a, 0xa1, 0x93, 0x19, 0xe7, 0x9f,
|
||||
0x14, 0x09, 0x05, 0xf5, 0x14, 0xac, 0xf1, 0xa9, 0x76, 0x7d, 0xc6, 0x2d, 0xf0, 0x5d, 0x50, 0xe9,
|
||||
0x59, 0x0e, 0xef, 0xd4, 0x82, 0xbe, 0x22, 0x58, 0x95, 0x53, 0xcb, 0x41, 0x61, 0x3b, 0x37, 0xe3,
|
||||
0x2b, 0x1e, 0xb3, 0xa4, 0x19, 0x5f, 0xa1, 0xb0, 0x5d, 0x7d, 0x00, 0x96, 0x84, 0xc7, 0xa4, 0x50,
|
||||
0x65, 0xba, 0x50, 0xa5, 0x40, 0xe8, 0x6f, 0xd7, 0xc0, 0x66, 0xcb, 0x35, 0x9b, 0x16, 0xf5, 0x03,
|
||||
0x1e, 0x2f, 0x3d, 0x30, 0xbb, 0x84, 0xbd, 0x85, 0xfc, 0x78, 0x02, 0xe6, 0xa9, 0x47, 0x0c, 0x91,
|
||||
0x16, 0xfb, 0x53, 0x62, 0x5b, 0xd0, 0xbf, 0xb6, 0x47, 0x8c, 0xc9, 0xb2, 0x0c, 0xbf, 0x10, 0x57,
|
||||
0x83, 0xcf, 0xc0, 0x22, 0x65, 0x98, 0x05, 0x54, 0xae, 0x70, 0xdd, 0xbb, 0xaf, 0xa9, 0xcb, 0xb9,
|
||||
0x93, 0x59, 0x1c, 0x7f, 0x23, 0xa1, 0xa9, 0xfe, 0x4b, 0x02, 0x37, 0x0a, 0x58, 0x8f, 0x2c, 0xca,
|
||||
0xe0, 0xb3, 0x5c, 0xc4, 0xb4, 0x57, 0x8b, 0x58, 0xc8, 0xe6, 0xf1, 0x8a, 0x17, 0x6f, 0xd4, 0x92,
|
||||
0x88, 0x56, 0x1b, 0x2c, 0x58, 0x8c, 0xf4, 0xa2, 0x54, 0xd4, 0x5e, 0x6f, 0x58, 0xfa, 0x9a, 0x90,
|
||||
0x5e, 0x38, 0x09, 0x45, 0xd0, 0x58, 0x4b, 0xfd, 0xe6, 0x5a, 0xe1, 0x70, 0xc2, 0x70, 0xc2, 0x73,
|
||||
0xb0, 0xda, 0xb3, 0x9c, 0x83, 0x3e, 0xb6, 0x6c, 0xdc, 0x11, 0xab, 0x67, 0x5a, 0x12, 0x84, 0x15,
|
||||
0x56, 0x1b, 0x57, 0x58, 0xed, 0xc4, 0x61, 0x67, 0x7e, 0x9b, 0xf9, 0x96, 0xd3, 0xd5, 0x37, 0x46,
|
||||
0x43, 0x65, 0xf5, 0x34, 0xa1, 0x84, 0x52, 0xba, 0xf0, 0xb7, 0xa0, 0x4a, 0x89, 0x4d, 0x0c, 0xe6,
|
||||
0xfa, 0xaf, 0x57, 0x21, 0x1e, 0xe1, 0x0e, 0xb1, 0xdb, 0x82, 0xaa, 0xaf, 0x86, 0x71, 0x8b, 0xbe,
|
||||
0x50, 0x2c, 0x09, 0x6d, 0xb0, 0xde, 0xc3, 0x57, 0x4f, 0x1d, 0x1c, 0x0f, 0xa4, 0xf2, 0x3d, 0x07,
|
||||
0x02, 0x47, 0x43, 0x65, 0xfd, 0x34, 0xa5, 0x85, 0x32, 0xda, 0xea, 0x3f, 0x17, 0xc0, 0x6e, 0x69,
|
||||
0x56, 0xc1, 0xcf, 0x00, 0x74, 0x3b, 0x94, 0xf8, 0x7d, 0x62, 0x3e, 0x18, 0xef, 0x41, 0x96, 0x1b,
|
||||
0x2d, 0xdc, 0x3d, 0x31, 0x41, 0xf0, 0x2c, 0x87, 0x40, 0x05, 0x2c, 0xf8, 0x27, 0x09, 0xac, 0x99,
|
||||
0x63, 0x37, 0xc4, 0x6c, 0xb9, 0x66, 0x94, 0x18, 0x0f, 0xbe, 0x4f, 0xbe, 0x6b, 0xcd, 0xa4, 0xd2,
|
||||
0x91, 0xc3, 0xfc, 0x81, 0xbe, 0x2d, 0x3a, 0xb4, 0x96, 0xb2, 0xa1, 0xb4, 0xd3, 0x70, 0x48, 0x66,
|
||||
0x2c, 0x49, 0xc5, 0x9e, 0xc6, 0x43, 0xbc, 0x30, 0x19, 0x52, 0x33, 0x87, 0x40, 0x05, 0x2c, 0xf8,
|
||||
0x73, 0xb0, 0x6e, 0x04, 0xbe, 0x4f, 0x1c, 0xf6, 0x90, 0x60, 0x9b, 0x5d, 0x0c, 0xe4, 0x79, 0xae,
|
||||
0xb3, 0x23, 0x74, 0xd6, 0x0f, 0x53, 0x56, 0x94, 0x41, 0x87, 0x7c, 0x93, 0x50, 0xcb, 0x27, 0x66,
|
||||
0xc4, 0x5f, 0x48, 0xf3, 0x9b, 0x29, 0x2b, 0xca, 0xa0, 0xe1, 0x7d, 0xb0, 0x4a, 0xae, 0x3c, 0x62,
|
||||
0x44, 0x01, 0x5d, 0xe4, 0xec, 0x2d, 0xc1, 0x5e, 0x3d, 0x4a, 0xd8, 0x50, 0x0a, 0x09, 0x0d, 0x00,
|
||||
0x0c, 0xd7, 0x31, 0xad, 0xf1, 0x3e, 0xb7, 0xc4, 0x27, 0xa2, 0xf1, 0x6a, 0x59, 0x7c, 0x18, 0xf1,
|
||||
0x26, 0xd5, 0x32, 0x6e, 0xa2, 0x28, 0x21, 0xbb, 0x67, 0x03, 0x98, 0x9f, 0x26, 0xb8, 0x01, 0x2a,
|
||||
0x97, 0x64, 0x30, 0xde, 0xdb, 0x50, 0xf8, 0x13, 0x7e, 0x0a, 0x16, 0xfa, 0xd8, 0x0e, 0x88, 0x58,
|
||||
0x4d, 0x1f, 0xbc, 0x5a, 0x3f, 0x9e, 0x58, 0x3d, 0x82, 0xc6, 0xc4, 0x9f, 0x5c, 0xbb, 0x2f, 0xa9,
|
||||
0x5f, 0x4b, 0xa0, 0xd6, 0x72, 0xcd, 0x36, 0x31, 0x02, 0xdf, 0x62, 0x83, 0x16, 0xcf, 0xa4, 0xb7,
|
||||
0xb0, 0x2b, 0xa0, 0xd4, 0xae, 0xf0, 0xd1, 0xf4, 0x6c, 0x4e, 0xf7, 0xae, 0x6c, 0x4f, 0x50, 0x9f,
|
||||
0x4b, 0x60, 0x3b, 0x87, 0x7e, 0x0b, 0x35, 0xfb, 0x97, 0xe9, 0x9a, 0xfd, 0xe1, 0xeb, 0x0c, 0xa6,
|
||||
0xa4, 0x62, 0x7f, 0x5d, 0x2b, 0x18, 0x0a, 0xaf, 0xd7, 0xe1, 0xf9, 0xd1, 0xb7, 0xfa, 0x96, 0x4d,
|
||||
0xba, 0xc4, 0xe4, 0x83, 0xa9, 0x26, 0xce, 0x8f, 0xb1, 0x05, 0x25, 0x50, 0x90, 0x82, 0x1d, 0x93,
|
||||
0x9c, 0xe3, 0xc0, 0x66, 0x07, 0xa6, 0x79, 0x88, 0x3d, 0xdc, 0xb1, 0x6c, 0x8b, 0x59, 0xe2, 0xc0,
|
||||
0xb3, 0xac, 0x7f, 0x32, 0x1a, 0x2a, 0x3b, 0xcd, 0x42, 0xc4, 0xcb, 0xa1, 0xf2, 0x6e, 0xfe, 0xbe,
|
||||
0xa0, 0xc5, 0x90, 0x01, 0x2a, 0x91, 0x86, 0x03, 0x20, 0xfb, 0xe4, 0x0f, 0x41, 0xb8, 0xf2, 0x9a,
|
||||
0xbe, 0xeb, 0xa5, 0xdc, 0x56, 0xb8, 0xdb, 0x9f, 0x8d, 0x86, 0x8a, 0x8c, 0x4a, 0x30, 0xb3, 0x1d,
|
||||
0x97, 0xca, 0xc3, 0x2f, 0xc0, 0x26, 0x16, 0x27, 0xfd, 0xa4, 0xd7, 0x79, 0xee, 0xf5, 0xfe, 0x68,
|
||||
0xa8, 0x6c, 0x1e, 0xe4, 0xcd, 0xb3, 0x1d, 0x16, 0x89, 0xc2, 0x06, 0x58, 0xea, 0xf3, 0x4b, 0x01,
|
||||
0x95, 0x17, 0xb8, 0xfe, 0xf6, 0x68, 0xa8, 0x2c, 0x8d, 0xef, 0x09, 0xa1, 0xe6, 0xe2, 0x71, 0x9b,
|
||||
0x1f, 0x35, 0x23, 0x14, 0xfc, 0x18, 0xac, 0x5c, 0xb8, 0x94, 0x3d, 0x26, 0xec, 0x4b, 0xd7, 0xbf,
|
||||
0xe4, 0xd5, 0xa7, 0xaa, 0x6f, 0x8a, 0x19, 0x5c, 0x79, 0x38, 0x31, 0xa1, 0x24, 0x0e, 0xfe, 0x1a,
|
||||
0x2c, 0x5f, 0x88, 0x83, 0x65, 0x54, 0x7a, 0x6e, 0x4d, 0x49, 0xb4, 0xd4, 0x21, 0x54, 0xaf, 0x09,
|
||||
0xf9, 0xe5, 0xa8, 0x99, 0xa2, 0x89, 0x1a, 0xfc, 0x01, 0x58, 0xe2, 0x1f, 0x27, 0x4d, 0xb9, 0xca,
|
||||
0x7b, 0x73, 0x5d, 0xc0, 0x97, 0x1e, 0x8e, 0x9b, 0x51, 0x64, 0x8f, 0xa0, 0x27, 0xad, 0x43, 0x79,
|
||||
0x39, 0x0f, 0x3d, 0x69, 0x1d, 0xa2, 0xc8, 0x0e, 0x9f, 0x81, 0x25, 0x4a, 0x1e, 0x59, 0x4e, 0x70,
|
||||
0x25, 0x03, 0xbe, 0xe4, 0x6e, 0x4f, 0xe9, 0x6e, 0xfb, 0x88, 0x23, 0x33, 0x47, 0xfa, 0x89, 0xba,
|
||||
0xb0, 0xa3, 0x48, 0x12, 0x9a, 0x60, 0xd9, 0x0f, 0x9c, 0x03, 0xfa, 0x94, 0x12, 0x5f, 0x5e, 0xc9,
|
||||
0x9d, 0x27, 0xb2, 0xfa, 0x28, 0xc2, 0x66, 0x3d, 0xc4, 0x91, 0x89, 0x11, 0x68, 0x22, 0x0c, 0x4d,
|
||||
0x00, 0xf8, 0x07, 0xbf, 0x39, 0xc8, 0x3b, 0x33, 0x4f, 0x9a, 0x28, 0x06, 0x67, 0xfd, 0xac, 0x87,
|
||||
0xcb, 0x73, 0x62, 0x46, 0x09, 0x5d, 0xf8, 0x67, 0x09, 0x40, 0x1a, 0x78, 0x9e, 0x4d, 0x7a, 0xc4,
|
||||
0x61, 0xd8, 0xe6, 0xad, 0x54, 0x5e, 0xe5, 0xee, 0x7e, 0x3a, 0x2d, 0x6a, 0x39, 0x52, 0xd6, 0x6d,
|
||||
0xbc, 0x37, 0xe7, 0xa1, 0xa8, 0xc0, 0x67, 0x38, 0x69, 0xe7, 0x62, 0xb4, 0x6b, 0x33, 0x27, 0xad,
|
||||
0xf8, 0x1e, 0x36, 0x99, 0x34, 0x61, 0x47, 0x91, 0x24, 0xfc, 0x1c, 0xec, 0x44, 0xb7, 0x54, 0xe4,
|
||||
0xba, 0xec, 0xd8, 0xb2, 0x09, 0x1d, 0x50, 0x46, 0x7a, 0xf2, 0x3a, 0x4f, 0xa6, 0xba, 0x60, 0xee,
|
||||
0xa0, 0x42, 0x14, 0x2a, 0x61, 0xc3, 0x1e, 0x50, 0xa2, 0x22, 0x14, 0xae, 0xd0, 0xb8, 0x0a, 0x1e,
|
||||
0x51, 0x03, 0xdb, 0xe3, 0xd3, 0xd7, 0x75, 0xee, 0xe0, 0xfd, 0xd1, 0x50, 0x51, 0x9a, 0xd3, 0xa1,
|
||||
0x68, 0x96, 0x16, 0xfc, 0x15, 0x90, 0x71, 0x99, 0x9f, 0x0d, 0xee, 0xe7, 0xff, 0xc2, 0xca, 0x56,
|
||||
0xea, 0xa0, 0x94, 0x0d, 0x3d, 0xb0, 0x81, 0xd3, 0xef, 0x05, 0x54, 0xae, 0xf1, 0xb5, 0xfe, 0xc1,
|
||||
0x94, 0x79, 0xc8, 0x3c, 0x31, 0xe8, 0xb2, 0x08, 0xe3, 0x46, 0xc6, 0x40, 0x51, 0x4e, 0x1d, 0x5e,
|
||||
0x01, 0x88, 0xb3, 0xcf, 0x1b, 0x54, 0x86, 0x33, 0x37, 0xb2, 0xdc, 0x9b, 0xc8, 0x24, 0xd5, 0x72,
|
||||
0x26, 0x8a, 0x0a, 0x7c, 0x40, 0x06, 0x6a, 0x38, 0xf3, 0x1c, 0x43, 0xe5, 0x1b, 0xdc, 0xf1, 0x0f,
|
||||
0x67, 0x3b, 0x8e, 0x39, 0xfa, 0xae, 0xf0, 0x5b, 0xcb, 0x5a, 0x28, 0xca, 0x3b, 0x80, 0x8f, 0xc0,
|
||||
0x96, 0x68, 0x7c, 0xea, 0x50, 0x7c, 0x4e, 0xda, 0x03, 0x6a, 0x30, 0x9b, 0xca, 0x9b, 0xbc, 0x76,
|
||||
0xcb, 0xa3, 0xa1, 0xb2, 0x75, 0x50, 0x60, 0x47, 0x85, 0x2c, 0xf8, 0x29, 0xd8, 0x38, 0x77, 0xfd,
|
||||
0x8e, 0x65, 0x9a, 0xc4, 0x89, 0x94, 0xb6, 0xb8, 0xd2, 0x56, 0x18, 0xff, 0xe3, 0x8c, 0x0d, 0xe5,
|
||||
0xd0, 0x90, 0x82, 0x6d, 0xa1, 0xdc, 0xf2, 0x5d, 0xe3, 0xd4, 0x0d, 0x1c, 0x16, 0x6e, 0x17, 0x54,
|
||||
0xde, 0x8e, 0xb7, 0xc8, 0xed, 0x83, 0x22, 0xc0, 0xcb, 0xa1, 0x72, 0xb3, 0x60, 0xbb, 0x4a, 0x81,
|
||||
0x50, 0xb1, 0x36, 0xb4, 0xc1, 0xaa, 0x78, 0x60, 0x3b, 0xb4, 0x31, 0xa5, 0xb2, 0xcc, 0x97, 0xfa,
|
||||
0xbd, 0xe9, 0x85, 0x2d, 0x86, 0x67, 0xd7, 0x3b, 0xbf, 0xf9, 0x25, 0x01, 0x28, 0xa5, 0xae, 0xfe,
|
||||
0x55, 0x02, 0xbb, 0xa5, 0x85, 0x11, 0xde, 0x4b, 0xbd, 0xda, 0xa8, 0x99, 0x57, 0x1b, 0x98, 0x27,
|
||||
0xbe, 0x81, 0x47, 0x9b, 0xaf, 0x24, 0x20, 0x97, 0xed, 0x10, 0xf0, 0xe3, 0x54, 0x07, 0xdf, 0xcb,
|
||||
0x74, 0xb0, 0x96, 0xe3, 0xbd, 0x81, 0xfe, 0x7d, 0x23, 0x81, 0x77, 0xa6, 0xcc, 0x40, 0x5c, 0x90,
|
||||
0x88, 0x99, 0x44, 0x3d, 0xc6, 0xe1, 0x52, 0x96, 0x78, 0x1e, 0x4d, 0x0a, 0x52, 0x01, 0x06, 0x95,
|
||||
0xb2, 0xe1, 0x53, 0x70, 0x43, 0x54, 0xc3, 0xac, 0x8d, 0x9f, 0xdc, 0x97, 0xf5, 0x77, 0x46, 0x43,
|
||||
0xe5, 0x46, 0xb3, 0x18, 0x82, 0xca, 0xb8, 0xea, 0xdf, 0x25, 0xb0, 0x53, 0xbc, 0xe5, 0xc3, 0x3b,
|
||||
0xa9, 0x70, 0x2b, 0x99, 0x70, 0x5f, 0xcf, 0xb0, 0x44, 0xb0, 0x7f, 0x07, 0xd6, 0xc5, 0xc1, 0x20,
|
||||
0xfd, 0x08, 0x99, 0x0a, 0x7a, 0xb8, 0x44, 0xc2, 0x33, 0xbd, 0x90, 0x88, 0xd2, 0x97, 0xdf, 0xf7,
|
||||
0xd3, 0x6d, 0x28, 0xa3, 0xa6, 0xfe, 0x43, 0x02, 0xef, 0xcd, 0xdc, 0x6c, 0xa1, 0x9e, 0xea, 0xba,
|
||||
0x96, 0xe9, 0x7a, 0xbd, 0x5c, 0xe0, 0xcd, 0xbc, 0x45, 0xea, 0xbf, 0x78, 0xfe, 0xa2, 0x3e, 0xf7,
|
||||
0xed, 0x8b, 0xfa, 0xdc, 0x77, 0x2f, 0xea, 0x73, 0x7f, 0x1c, 0xd5, 0xa5, 0xe7, 0xa3, 0xba, 0xf4,
|
||||
0xed, 0xa8, 0x2e, 0x7d, 0x37, 0xaa, 0x4b, 0xff, 0x19, 0xd5, 0xa5, 0xbf, 0xfc, 0xb7, 0x3e, 0xf7,
|
||||
0x9b, 0xdd, 0xd2, 0xff, 0x20, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0xec, 0x71, 0xd7, 0x62, 0xb8,
|
||||
0x18, 0x00, 0x00,
|
||||
0x15, 0x16, 0x4c, 0x5d, 0xa8, 0xd5, 0xc5, 0xe2, 0xea, 0x62, 0x48, 0x69, 0x08, 0x07, 0x99, 0xe9,
|
||||
0xb8, 0x69, 0x0a, 0xc6, 0xb2, 0xe3, 0x7a, 0x9a, 0x5e, 0x2c, 0x88, 0x92, 0xad, 0x8c, 0x65, 0xb1,
|
||||
0x4b, 0x2b, 0xd3, 0x76, 0xdc, 0x4e, 0x97, 0xc0, 0x8a, 0x44, 0x04, 0x02, 0x28, 0x76, 0xc1, 0x88,
|
||||
0x6f, 0x79, 0xe8, 0x43, 0x1f, 0xfb, 0x07, 0x32, 0xfd, 0x01, 0x9d, 0x3e, 0xf5, 0x47, 0xd4, 0x99,
|
||||
0xe9, 0x74, 0xd2, 0xb7, 0x4c, 0x1f, 0x38, 0x35, 0xfb, 0x2f, 0xfc, 0xd4, 0xc1, 0x72, 0x01, 0x12,
|
||||
0x37, 0xd2, 0xce, 0x8c, 0xfd, 0x46, 0xec, 0xf9, 0xbe, 0xef, 0xec, 0x9e, 0xdd, 0x3d, 0x67, 0x77,
|
||||
0x09, 0xf4, 0xcb, 0xfb, 0x54, 0xb3, 0xdc, 0xda, 0x65, 0xd0, 0x22, 0xbe, 0x43, 0x18, 0xa1, 0xb5,
|
||||
0x1e, 0x71, 0x4c, 0xd7, 0xaf, 0x09, 0x03, 0xf6, 0xac, 0x9a, 0xe7, 0xda, 0x96, 0xd1, 0xaf, 0xf5,
|
||||
0x6e, 0xb7, 0x08, 0xc3, 0xb7, 0x6b, 0x6d, 0xe2, 0x10, 0x1f, 0x33, 0x62, 0x6a, 0x9e, 0xef, 0x32,
|
||||
0x17, 0xee, 0x8e, 0xa0, 0x1a, 0xf6, 0x2c, 0x6d, 0x04, 0xd5, 0x04, 0x74, 0xef, 0x47, 0x6d, 0x8b,
|
||||
0x75, 0x82, 0x96, 0x66, 0xb8, 0xdd, 0x5a, 0xdb, 0x6d, 0xbb, 0x35, 0xce, 0x68, 0x05, 0x17, 0xfc,
|
||||
0x8b, 0x7f, 0xf0, 0x5f, 0x23, 0xa5, 0x3d, 0x75, 0xc2, 0xa9, 0xe1, 0xfa, 0xa4, 0xd6, 0xcb, 0x78,
|
||||
0xdb, 0xbb, 0x3b, 0xc6, 0x74, 0xb1, 0xd1, 0xb1, 0x1c, 0xe2, 0xf7, 0x6b, 0xde, 0x65, 0x3b, 0x6c,
|
||||
0xa0, 0xb5, 0x2e, 0x61, 0x38, 0x8f, 0x55, 0x2b, 0x62, 0xf9, 0x81, 0xc3, 0xac, 0x2e, 0xc9, 0x10,
|
||||
0xee, 0xcd, 0x22, 0x50, 0xa3, 0x43, 0xba, 0x38, 0xc3, 0xbb, 0x53, 0xc4, 0x0b, 0x98, 0x65, 0xd7,
|
||||
0x2c, 0x87, 0x51, 0xe6, 0xa7, 0x49, 0xea, 0x5d, 0xb0, 0x71, 0x60, 0xdb, 0xee, 0x17, 0xc4, 0x3c,
|
||||
0x6c, 0x9e, 0xd4, 0x7d, 0xab, 0x47, 0x7c, 0x78, 0x13, 0xcc, 0x3b, 0xb8, 0x4b, 0x64, 0xe9, 0xa6,
|
||||
0x74, 0x6b, 0x59, 0x5f, 0x7d, 0x3e, 0x50, 0xe6, 0x86, 0x03, 0x65, 0xfe, 0x09, 0xee, 0x12, 0xc4,
|
||||
0x2d, 0xea, 0x27, 0xa0, 0x22, 0x58, 0xc7, 0x36, 0xb9, 0xfa, 0xcc, 0xb5, 0x83, 0x2e, 0x81, 0xdf,
|
||||
0x07, 0x8b, 0x26, 0x17, 0x10, 0xc4, 0x75, 0x41, 0x5c, 0x1c, 0xc9, 0x22, 0x61, 0x55, 0x29, 0xb8,
|
||||
0x2e, 0xc8, 0x8f, 0x5c, 0xca, 0x1a, 0x98, 0x75, 0xe0, 0x3e, 0x00, 0x1e, 0x66, 0x9d, 0x86, 0x4f,
|
||||
0x2e, 0xac, 0x2b, 0x41, 0x87, 0x82, 0x0e, 0x1a, 0xb1, 0x05, 0x4d, 0xa0, 0xe0, 0x87, 0xa0, 0xec,
|
||||
0x13, 0x6c, 0x9e, 0x39, 0x76, 0x5f, 0xbe, 0x76, 0x53, 0xba, 0x55, 0xd6, 0x37, 0x04, 0xa3, 0x8c,
|
||||
0x44, 0x3b, 0x8a, 0x11, 0xea, 0x7f, 0x24, 0x50, 0x3e, 0xea, 0x59, 0x06, 0xb3, 0x5c, 0x07, 0xfe,
|
||||
0x1e, 0x94, 0xc3, 0xd9, 0x32, 0x31, 0xc3, 0xdc, 0xd9, 0xca, 0xfe, 0x47, 0xda, 0x78, 0x25, 0xc5,
|
||||
0xc1, 0xd3, 0xbc, 0xcb, 0x76, 0xd8, 0x40, 0xb5, 0x10, 0xad, 0xf5, 0x6e, 0x6b, 0x67, 0xad, 0xcf,
|
||||
0x89, 0xc1, 0x4e, 0x09, 0xc3, 0xe3, 0xee, 0x8d, 0xdb, 0x50, 0xac, 0x0a, 0x6d, 0xb0, 0x66, 0x12,
|
||||
0x9b, 0x30, 0x72, 0xe6, 0x85, 0x1e, 0x29, 0xef, 0xe1, 0xca, 0xfe, 0x9d, 0x57, 0x73, 0x53, 0x9f,
|
||||
0xa4, 0xea, 0x95, 0xe1, 0x40, 0x59, 0x4b, 0x34, 0xa1, 0xa4, 0xb8, 0xfa, 0x95, 0x04, 0x76, 0x8e,
|
||||
0x9b, 0x0f, 0x7d, 0x37, 0xf0, 0x9a, 0x2c, 0x9c, 0xdd, 0x76, 0x5f, 0x98, 0xe0, 0x8f, 0xc1, 0xbc,
|
||||
0x1f, 0xd8, 0xd1, 0x5c, 0xbe, 0x1f, 0xcd, 0x25, 0x0a, 0x6c, 0xf2, 0x72, 0xa0, 0x6c, 0xa6, 0x58,
|
||||
0x4f, 0xfb, 0x1e, 0x41, 0x9c, 0x00, 0x3f, 0x05, 0x8b, 0x3e, 0x76, 0xda, 0x24, 0xec, 0x7a, 0xe9,
|
||||
0xd6, 0xca, 0xbe, 0xaa, 0x15, 0xee, 0x35, 0xed, 0xa4, 0x8e, 0x42, 0xe8, 0x78, 0xc6, 0xf9, 0x27,
|
||||
0x45, 0x42, 0x41, 0x3d, 0x05, 0x6b, 0x7c, 0xaa, 0x5d, 0x9f, 0x71, 0x0b, 0x7c, 0x17, 0x94, 0xba,
|
||||
0x96, 0xc3, 0x3b, 0xb5, 0xa0, 0xaf, 0x08, 0x56, 0xe9, 0xd4, 0x72, 0x50, 0xd8, 0xce, 0xcd, 0xf8,
|
||||
0x8a, 0xc7, 0x6c, 0xd2, 0x8c, 0xaf, 0x50, 0xd8, 0xae, 0x3e, 0x04, 0x4b, 0xc2, 0xe3, 0xa4, 0x50,
|
||||
0x69, 0xba, 0x50, 0x29, 0x47, 0xe8, 0xaf, 0xd7, 0xc0, 0x66, 0xc3, 0x35, 0xeb, 0x16, 0xf5, 0x03,
|
||||
0x1e, 0x2f, 0x3d, 0x30, 0xdb, 0x84, 0xbd, 0x85, 0xf5, 0xf1, 0x14, 0xcc, 0x53, 0x8f, 0x18, 0x62,
|
||||
0x59, 0xec, 0x4f, 0x89, 0x6d, 0x4e, 0xff, 0x9a, 0x1e, 0x31, 0xc6, 0xdb, 0x32, 0xfc, 0x42, 0x5c,
|
||||
0x0d, 0x3e, 0x03, 0x8b, 0x94, 0x61, 0x16, 0x50, 0xb9, 0xc4, 0x75, 0xef, 0xbe, 0xa6, 0x2e, 0xe7,
|
||||
0x8e, 0x67, 0x71, 0xf4, 0x8d, 0x84, 0xa6, 0xfa, 0x4f, 0x09, 0xdc, 0xc8, 0x61, 0x3d, 0xb6, 0x28,
|
||||
0x83, 0xcf, 0x32, 0x11, 0xd3, 0x5e, 0x2d, 0x62, 0x21, 0x9b, 0xc7, 0x2b, 0xde, 0xbc, 0x51, 0xcb,
|
||||
0x44, 0xb4, 0x9a, 0x60, 0xc1, 0x62, 0xa4, 0x1b, 0x2d, 0x45, 0xed, 0xf5, 0x86, 0xa5, 0xaf, 0x09,
|
||||
0xe9, 0x85, 0x93, 0x50, 0x04, 0x8d, 0xb4, 0xd4, 0x7f, 0x97, 0x72, 0x87, 0x13, 0x86, 0x13, 0x5e,
|
||||
0x80, 0xd5, 0xae, 0xe5, 0x1c, 0xf4, 0xb0, 0x65, 0xe3, 0x96, 0xd8, 0x3d, 0xd3, 0x16, 0x41, 0x98,
|
||||
0x61, 0xb5, 0x51, 0x86, 0xd5, 0x4e, 0x1c, 0x76, 0xe6, 0x37, 0x99, 0x6f, 0x39, 0x6d, 0x7d, 0x63,
|
||||
0x38, 0x50, 0x56, 0x4f, 0x27, 0x94, 0x50, 0x42, 0x17, 0xfe, 0x16, 0x94, 0x29, 0xb1, 0x89, 0xc1,
|
||||
0x5c, 0xff, 0xf5, 0x32, 0xc4, 0x63, 0xdc, 0x22, 0x76, 0x53, 0x50, 0xf5, 0xd5, 0x30, 0x6e, 0xd1,
|
||||
0x17, 0x8a, 0x25, 0xa1, 0x0d, 0xd6, 0xbb, 0xf8, 0xea, 0xdc, 0xc1, 0xf1, 0x40, 0x4a, 0xdf, 0x71,
|
||||
0x20, 0x70, 0x38, 0x50, 0xd6, 0x4f, 0x13, 0x5a, 0x28, 0xa5, 0x0d, 0xbf, 0x94, 0xc0, 0x5e, 0xe0,
|
||||
0x74, 0x08, 0xb6, 0x59, 0xa7, 0xdf, 0x70, 0xcd, 0x28, 0xdd, 0x36, 0xf8, 0x0c, 0xc9, 0xf3, 0x3c,
|
||||
0x03, 0x3d, 0x18, 0x0e, 0x94, 0xbd, 0xf3, 0x42, 0xd4, 0xcb, 0x81, 0x52, 0x2d, 0xb6, 0xf2, 0xf4,
|
||||
0x34, 0xc5, 0x87, 0xfa, 0x8f, 0x05, 0xb0, 0x5b, 0xb8, 0xb0, 0xe1, 0xa7, 0x00, 0xba, 0x2d, 0x4a,
|
||||
0xfc, 0x1e, 0x31, 0x1f, 0x8e, 0xca, 0xa0, 0xe5, 0x46, 0xb9, 0x63, 0x4f, 0xac, 0x11, 0x78, 0x96,
|
||||
0x41, 0xa0, 0x1c, 0x16, 0xfc, 0xa3, 0x04, 0xd6, 0xcc, 0x91, 0x1b, 0x62, 0x36, 0x5c, 0x33, 0x5a,
|
||||
0x9b, 0x0f, 0xbf, 0xcb, 0x96, 0xd3, 0xea, 0x93, 0x4a, 0x47, 0x0e, 0xf3, 0xfb, 0xfa, 0xb6, 0xe8,
|
||||
0xd0, 0x5a, 0xc2, 0x86, 0x92, 0x4e, 0xc3, 0x21, 0x99, 0xb1, 0x24, 0x15, 0x65, 0x95, 0xcf, 0xf2,
|
||||
0xc2, 0x78, 0x48, 0xf5, 0x0c, 0x02, 0xe5, 0xb0, 0xe0, 0xcf, 0xc1, 0xba, 0x11, 0xf8, 0x3e, 0x71,
|
||||
0xd8, 0xa3, 0x51, 0x7c, 0xf9, 0x94, 0x2d, 0xe8, 0x3b, 0x42, 0x67, 0xfd, 0x30, 0x61, 0x45, 0x29,
|
||||
0x74, 0xc8, 0x37, 0x09, 0xb5, 0x7c, 0x62, 0x46, 0xfc, 0x85, 0x24, 0xbf, 0x9e, 0xb0, 0xa2, 0x14,
|
||||
0x1a, 0xde, 0x07, 0xab, 0xe4, 0xca, 0x23, 0x46, 0x14, 0xd0, 0x45, 0xce, 0xde, 0x12, 0xec, 0xd5,
|
||||
0xa3, 0x09, 0x1b, 0x4a, 0x20, 0xa1, 0x01, 0x80, 0xe1, 0x3a, 0xa6, 0x35, 0x2a, 0xb5, 0x4b, 0x7c,
|
||||
0x22, 0x6a, 0xaf, 0xb6, 0x91, 0x0e, 0x23, 0xde, 0x38, 0x61, 0xc7, 0x4d, 0x14, 0x4d, 0xc8, 0xee,
|
||||
0xd9, 0x00, 0x66, 0xa7, 0x09, 0x6e, 0x80, 0xd2, 0x25, 0xe9, 0x8f, 0xca, 0x2b, 0x0a, 0x7f, 0xc2,
|
||||
0x07, 0x60, 0xa1, 0x87, 0xed, 0x80, 0x88, 0x0d, 0xfd, 0xc1, 0xab, 0xf5, 0xe3, 0xa9, 0xd5, 0x25,
|
||||
0x68, 0x44, 0xfc, 0xc9, 0xb5, 0xfb, 0x92, 0xfa, 0xb5, 0x04, 0x2a, 0x0d, 0xd7, 0x6c, 0x12, 0x23,
|
||||
0xf0, 0x2d, 0xd6, 0x1f, 0xad, 0xef, 0xb7, 0x50, 0x98, 0x50, 0xa2, 0x30, 0x7d, 0x34, 0x7d, 0x35,
|
||||
0x27, 0x7b, 0x57, 0x54, 0x96, 0xd4, 0xe7, 0x12, 0xd8, 0xce, 0xa0, 0xdf, 0x42, 0xd9, 0xf8, 0x65,
|
||||
0xb2, 0x6c, 0x7c, 0xf8, 0x3a, 0x83, 0x29, 0x28, 0x1a, 0x5f, 0x57, 0x72, 0x86, 0xc2, 0x4b, 0x46,
|
||||
0x78, 0x84, 0xf5, 0xad, 0x9e, 0x65, 0x93, 0x36, 0x31, 0xf9, 0x60, 0xca, 0x13, 0x47, 0xd8, 0xd8,
|
||||
0x82, 0x26, 0x50, 0x90, 0x82, 0x1d, 0x93, 0x5c, 0xe0, 0xc0, 0x66, 0x07, 0xa6, 0x79, 0x88, 0x3d,
|
||||
0xdc, 0xb2, 0x6c, 0x8b, 0x59, 0xe2, 0xcc, 0xb5, 0xac, 0x7f, 0x32, 0x1c, 0x28, 0x3b, 0xf5, 0x5c,
|
||||
0xc4, 0xcb, 0x81, 0xf2, 0x6e, 0xf6, 0xca, 0xa2, 0xc5, 0x90, 0x3e, 0x2a, 0x90, 0x86, 0x7d, 0x20,
|
||||
0xfb, 0xe4, 0x0f, 0x41, 0xb8, 0xf3, 0xea, 0xbe, 0xeb, 0x25, 0xdc, 0x96, 0xb8, 0xdb, 0x9f, 0x0d,
|
||||
0x07, 0x8a, 0x8c, 0x0a, 0x30, 0xb3, 0x1d, 0x17, 0xca, 0xc3, 0xcf, 0xc1, 0x26, 0x16, 0x97, 0x8d,
|
||||
0x49, 0xaf, 0xf3, 0xdc, 0xeb, 0xfd, 0xe1, 0x40, 0xd9, 0x3c, 0xc8, 0x9a, 0x67, 0x3b, 0xcc, 0x13,
|
||||
0x85, 0x35, 0xb0, 0xd4, 0xe3, 0xf7, 0x12, 0x2a, 0x2f, 0x70, 0xfd, 0xed, 0xe1, 0x40, 0x59, 0x1a,
|
||||
0x5d, 0x55, 0x42, 0xcd, 0xc5, 0xe3, 0x26, 0x2f, 0x27, 0x11, 0x0a, 0x7e, 0x0c, 0x56, 0x3a, 0x2e,
|
||||
0x65, 0x4f, 0x08, 0xfb, 0xc2, 0xf5, 0x2f, 0x79, 0xf6, 0x29, 0xeb, 0x9b, 0x62, 0x06, 0x57, 0x1e,
|
||||
0x8d, 0x4d, 0x68, 0x12, 0x07, 0x7f, 0x0d, 0x96, 0x3b, 0xe2, 0x6c, 0x1b, 0xa5, 0x9e, 0x5b, 0x53,
|
||||
0x16, 0x5a, 0xe2, 0x1c, 0xac, 0x57, 0x84, 0xfc, 0x72, 0xd4, 0x4c, 0xd1, 0x58, 0x0d, 0xfe, 0x00,
|
||||
0x2c, 0xf1, 0x8f, 0x93, 0xba, 0x5c, 0xe6, 0xbd, 0xb9, 0x2e, 0xe0, 0x4b, 0x8f, 0x46, 0xcd, 0x28,
|
||||
0xb2, 0x47, 0xd0, 0x93, 0xc6, 0xa1, 0xbc, 0x9c, 0x85, 0x9e, 0x34, 0x0e, 0x51, 0x64, 0x87, 0xcf,
|
||||
0xc0, 0x12, 0x25, 0x8f, 0x2d, 0x27, 0xb8, 0x92, 0x01, 0xdf, 0x72, 0xb7, 0xa7, 0x74, 0xb7, 0x79,
|
||||
0xc4, 0x91, 0xa9, 0x5b, 0xc5, 0x58, 0x5d, 0xd8, 0x51, 0x24, 0x09, 0x4d, 0xb0, 0xec, 0x07, 0xce,
|
||||
0x01, 0x3d, 0xa7, 0xc4, 0x97, 0x57, 0x32, 0x47, 0x9a, 0xb4, 0x3e, 0x8a, 0xb0, 0x69, 0x0f, 0x71,
|
||||
0x64, 0x62, 0x04, 0x1a, 0x0b, 0x43, 0x13, 0x00, 0xfe, 0xc1, 0x2f, 0x2f, 0xf2, 0xce, 0xcc, 0xc3,
|
||||
0x2e, 0x8a, 0xc1, 0x69, 0x3f, 0xeb, 0xe1, 0xf6, 0x1c, 0x9b, 0xd1, 0x84, 0x2e, 0xfc, 0x93, 0x04,
|
||||
0x20, 0x0d, 0x3c, 0xcf, 0x26, 0x5d, 0xe2, 0x30, 0x6c, 0xf3, 0x56, 0x2a, 0xaf, 0x72, 0x77, 0x3f,
|
||||
0x9d, 0x16, 0xb5, 0x0c, 0x29, 0xed, 0x36, 0xae, 0xcd, 0x59, 0x28, 0xca, 0xf1, 0x19, 0x4e, 0xda,
|
||||
0x85, 0x18, 0xed, 0xda, 0xcc, 0x49, 0xcb, 0xbf, 0x0a, 0x8e, 0x27, 0x4d, 0xd8, 0x51, 0x24, 0x09,
|
||||
0x3f, 0x03, 0x3b, 0xd1, 0x45, 0x19, 0xb9, 0x2e, 0x3b, 0xb6, 0x6c, 0x42, 0xfb, 0x94, 0x91, 0xae,
|
||||
0xbc, 0xce, 0x17, 0x53, 0x55, 0x30, 0x77, 0x50, 0x2e, 0x0a, 0x15, 0xb0, 0x61, 0x17, 0x28, 0x51,
|
||||
0x12, 0x0a, 0x77, 0x68, 0x9c, 0x05, 0x8f, 0xa8, 0x81, 0xed, 0xd1, 0xe9, 0xeb, 0x3a, 0x77, 0xf0,
|
||||
0xfe, 0x70, 0xa0, 0x28, 0xf5, 0xe9, 0x50, 0x34, 0x4b, 0x0b, 0xfe, 0x0a, 0xc8, 0xb8, 0xc8, 0xcf,
|
||||
0x06, 0xf7, 0xf3, 0xbd, 0x30, 0xb3, 0x15, 0x3a, 0x28, 0x64, 0x43, 0x0f, 0x6c, 0xe0, 0xe4, 0x93,
|
||||
0x05, 0x95, 0x2b, 0x7c, 0xaf, 0x7f, 0x30, 0x65, 0x1e, 0x52, 0xaf, 0x1c, 0xba, 0x2c, 0xc2, 0xb8,
|
||||
0x91, 0x32, 0x50, 0x94, 0x51, 0x87, 0x57, 0x00, 0xe2, 0xf4, 0x0b, 0x0b, 0x95, 0xe1, 0xcc, 0x42,
|
||||
0x96, 0x79, 0x96, 0x19, 0x2f, 0xb5, 0x8c, 0x89, 0xa2, 0x1c, 0x1f, 0x90, 0x81, 0x0a, 0x4e, 0xbd,
|
||||
0x08, 0x51, 0xf9, 0x06, 0x77, 0xfc, 0xc3, 0xd9, 0x8e, 0x63, 0x8e, 0xbe, 0x2b, 0xfc, 0x56, 0xd2,
|
||||
0x16, 0x8a, 0xb2, 0x0e, 0xe0, 0x63, 0xb0, 0x25, 0x1a, 0xcf, 0x1d, 0x8a, 0x2f, 0x48, 0xb3, 0x4f,
|
||||
0x0d, 0x66, 0x53, 0x79, 0x93, 0xe7, 0x6e, 0x79, 0x38, 0x50, 0xb6, 0x0e, 0x72, 0xec, 0x28, 0x97,
|
||||
0x05, 0x1f, 0x80, 0x8d, 0x0b, 0xd7, 0x6f, 0x59, 0xa6, 0x49, 0x9c, 0x48, 0x69, 0x8b, 0x2b, 0x6d,
|
||||
0x85, 0xf1, 0x3f, 0x4e, 0xd9, 0x50, 0x06, 0x0d, 0x29, 0xd8, 0x16, 0xca, 0x0d, 0xdf, 0x35, 0x4e,
|
||||
0xdd, 0xc0, 0x61, 0x61, 0xb9, 0xa0, 0xf2, 0x76, 0x5c, 0x22, 0xb7, 0x0f, 0xf2, 0x00, 0x2f, 0x07,
|
||||
0xca, 0xcd, 0x9c, 0x72, 0x95, 0x00, 0xa1, 0x7c, 0x6d, 0x68, 0x83, 0x55, 0xf1, 0xc6, 0x77, 0x68,
|
||||
0x63, 0x4a, 0x65, 0x99, 0x6f, 0xf5, 0x7b, 0xd3, 0x13, 0x5b, 0x0c, 0x4f, 0xef, 0x77, 0x7e, 0xf9,
|
||||
0x9c, 0x04, 0xa0, 0x84, 0xba, 0xfa, 0x17, 0x09, 0xec, 0x16, 0x26, 0x46, 0x78, 0x2f, 0xf1, 0x70,
|
||||
0xa4, 0xa6, 0x1e, 0x8e, 0x60, 0x96, 0xf8, 0x06, 0xde, 0x8d, 0xbe, 0x92, 0x80, 0x5c, 0x54, 0x21,
|
||||
0xe0, 0xc7, 0x89, 0x0e, 0xbe, 0x97, 0xea, 0x60, 0x25, 0xc3, 0x7b, 0x03, 0xfd, 0xfb, 0x97, 0x04,
|
||||
0xde, 0x99, 0x32, 0x03, 0x71, 0x42, 0x22, 0xe6, 0x24, 0xea, 0x09, 0x0e, 0xb7, 0xb2, 0xc4, 0xd7,
|
||||
0xd1, 0x38, 0x21, 0xe5, 0x60, 0x50, 0x21, 0x1b, 0x9e, 0x83, 0x1b, 0x22, 0x1b, 0xa6, 0x6d, 0xfc,
|
||||
0xe4, 0xbe, 0xac, 0xbf, 0x33, 0x1c, 0x28, 0x37, 0xea, 0xf9, 0x10, 0x54, 0xc4, 0x55, 0xff, 0x26,
|
||||
0x81, 0x9d, 0xfc, 0x92, 0x0f, 0xef, 0x24, 0xc2, 0xad, 0xa4, 0xc2, 0x7d, 0x3d, 0xc5, 0x12, 0xc1,
|
||||
0xfe, 0x1d, 0x58, 0x17, 0x07, 0x83, 0xe4, 0x3b, 0x68, 0x22, 0xe8, 0xe1, 0x16, 0x09, 0xcf, 0xf4,
|
||||
0x42, 0x22, 0x5a, 0xbe, 0xfc, 0xc9, 0x21, 0xd9, 0x86, 0x52, 0x6a, 0xea, 0xdf, 0x25, 0xf0, 0xde,
|
||||
0xcc, 0x62, 0x0b, 0xf5, 0x44, 0xd7, 0xb5, 0x54, 0xd7, 0xab, 0xc5, 0x02, 0x6f, 0xe6, 0x39, 0x54,
|
||||
0xff, 0xc5, 0xf3, 0x17, 0xd5, 0xb9, 0x6f, 0x5e, 0x54, 0xe7, 0xbe, 0x7d, 0x51, 0x9d, 0xfb, 0x72,
|
||||
0x58, 0x95, 0x9e, 0x0f, 0xab, 0xd2, 0x37, 0xc3, 0xaa, 0xf4, 0xed, 0xb0, 0x2a, 0xfd, 0x77, 0x58,
|
||||
0x95, 0xfe, 0xfc, 0xbf, 0xea, 0xdc, 0x6f, 0x76, 0x0b, 0xff, 0x06, 0xf9, 0x7f, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xb4, 0x84, 0x53, 0xfb, 0x3b, 0x19, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *AllowedCSIDriver) Marshal() (dAtA []byte, err error) {
|
||||
@ -1089,6 +1091,13 @@ func (m *PodDisruptionBudgetSpec) MarshalToSizedBuffer(dAtA []byte) (int, error)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.UnhealthyPodEvictionPolicy != nil {
|
||||
i -= len(*m.UnhealthyPodEvictionPolicy)
|
||||
copy(dAtA[i:], *m.UnhealthyPodEvictionPolicy)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.UnhealthyPodEvictionPolicy)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.MaxUnavailable != nil {
|
||||
{
|
||||
size, err := m.MaxUnavailable.MarshalToSizedBuffer(dAtA[:i])
|
||||
@ -1937,6 +1946,10 @@ func (m *PodDisruptionBudgetSpec) Size() (n int) {
|
||||
l = m.MaxUnavailable.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
if m.UnhealthyPodEvictionPolicy != nil {
|
||||
l = len(*m.UnhealthyPodEvictionPolicy)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -2308,6 +2321,7 @@ func (this *PodDisruptionBudgetSpec) String() string {
|
||||
`MinAvailable:` + strings.Replace(fmt.Sprintf("%v", this.MinAvailable), "IntOrString", "intstr.IntOrString", 1) + `,`,
|
||||
`Selector:` + strings.Replace(fmt.Sprintf("%v", this.Selector), "LabelSelector", "v1.LabelSelector", 1) + `,`,
|
||||
`MaxUnavailable:` + strings.Replace(fmt.Sprintf("%v", this.MaxUnavailable), "IntOrString", "intstr.IntOrString", 1) + `,`,
|
||||
`UnhealthyPodEvictionPolicy:` + valueToStringGenerated(this.UnhealthyPodEvictionPolicy) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@ -3581,6 +3595,39 @@ func (m *PodDisruptionBudgetSpec) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field UnhealthyPodEvictionPolicy", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := UnhealthyPodEvictionPolicyType(dAtA[iNdEx:postIndex])
|
||||
m.UnhealthyPodEvictionPolicy = &s
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
@ -153,6 +153,34 @@ message PodDisruptionBudgetSpec {
|
||||
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 3;
|
||||
|
||||
// UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction. Current implementation considers healthy pods,
|
||||
// as pods that have status.conditions item with type="Ready",status="True".
|
||||
//
|
||||
// Valid policies are IfHealthyBudget and AlwaysAllow.
|
||||
// If no policy is specified, the default behavior will be used,
|
||||
// which corresponds to the IfHealthyBudget policy.
|
||||
//
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// Additional policies may be added in the future.
|
||||
// Clients making eviction decisions should disallow eviction of unhealthy pods
|
||||
// if they encounter an unrecognized policy in this field.
|
||||
//
|
||||
// This field is alpha-level. The eviction API uses this field when
|
||||
// the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).
|
||||
// +optional
|
||||
optional string unhealthyPodEvictionPolicy = 4;
|
||||
}
|
||||
|
||||
// PodDisruptionBudgetStatus represents information about the status of a
|
||||
|
@ -45,8 +45,56 @@ type PodDisruptionBudgetSpec struct {
|
||||
// by specifying 0. This is a mutually exclusive setting with "minAvailable".
|
||||
// +optional
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,3,opt,name=maxUnavailable"`
|
||||
|
||||
// UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction. Current implementation considers healthy pods,
|
||||
// as pods that have status.conditions item with type="Ready",status="True".
|
||||
//
|
||||
// Valid policies are IfHealthyBudget and AlwaysAllow.
|
||||
// If no policy is specified, the default behavior will be used,
|
||||
// which corresponds to the IfHealthyBudget policy.
|
||||
//
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
//
|
||||
// Additional policies may be added in the future.
|
||||
// Clients making eviction decisions should disallow eviction of unhealthy pods
|
||||
// if they encounter an unrecognized policy in this field.
|
||||
//
|
||||
// This field is alpha-level. The eviction API uses this field when
|
||||
// the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).
|
||||
// +optional
|
||||
UnhealthyPodEvictionPolicy *UnhealthyPodEvictionPolicyType `json:"unhealthyPodEvictionPolicy,omitempty" protobuf:"bytes,4,opt,name=unhealthyPodEvictionPolicy"`
|
||||
}
|
||||
|
||||
// UnhealthyPodEvictionPolicyType defines the criteria for when unhealthy pods
|
||||
// should be considered for eviction.
|
||||
// +enum
|
||||
type UnhealthyPodEvictionPolicyType string
|
||||
|
||||
const (
|
||||
// IfHealthyBudget policy means that running pods (status.phase="Running"),
|
||||
// but not yet healthy can be evicted only if the guarded application is not
|
||||
// disrupted (status.currentHealthy is at least equal to status.desiredHealthy).
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
IfHealthyBudget UnhealthyPodEvictionPolicyType = "IfHealthyBudget"
|
||||
|
||||
// AlwaysAllow policy means that all running pods (status.phase="Running"),
|
||||
// but not yet healthy are considered disrupted and can be evicted regardless
|
||||
// of whether the criteria in a PDB is met. This means perspective running
|
||||
// pods of a disrupted application might not get a chance to become healthy.
|
||||
// Healthy pods will be subject to the PDB for eviction.
|
||||
AlwaysAllow UnhealthyPodEvictionPolicyType = "AlwaysAllow"
|
||||
)
|
||||
|
||||
// PodDisruptionBudgetStatus represents information about the status of a
|
||||
// PodDisruptionBudget. Status may trail the actual state of a system.
|
||||
type PodDisruptionBudgetStatus struct {
|
||||
|
@ -121,6 +121,7 @@ var map_PodDisruptionBudgetSpec = map[string]string{
|
||||
"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 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\".",
|
||||
"unhealthyPodEvictionPolicy": "UnhealthyPodEvictionPolicy defines the criteria for when unhealthy pods should be considered for eviction. Current implementation considers healthy pods, as pods that have status.conditions item with type=\"Ready\",status=\"True\".\n\nValid policies are IfHealthyBudget and AlwaysAllow. If no policy is specified, the default behavior will be used, which corresponds to the IfHealthyBudget policy.\n\nIfHealthyBudget policy means that running pods (status.phase=\"Running\"), but not yet healthy can be evicted only if the guarded application is not disrupted (status.currentHealthy is at least equal to status.desiredHealthy). Healthy pods will be subject to the PDB for eviction.\n\nAlwaysAllow policy means that all running pods (status.phase=\"Running\"), but not yet healthy are considered disrupted and can be evicted regardless of whether the criteria in a PDB is met. This means perspective running pods of a disrupted application might not get a chance to become healthy. Healthy pods will be subject to the PDB for eviction.\n\nAdditional policies may be added in the future. Clients making eviction decisions should disallow eviction of unhealthy pods if they encounter an unrecognized policy in this field.\n\nThis field is alpha-level. The eviction API uses this field when the feature gate PDBUnhealthyPodEvictionPolicy is enabled (disabled by default).",
|
||||
}
|
||||
|
||||
func (PodDisruptionBudgetSpec) SwaggerDoc() map[string]string {
|
||||
|
@ -239,6 +239,11 @@ func (in *PodDisruptionBudgetSpec) DeepCopyInto(out *PodDisruptionBudgetSpec) {
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
if in.UnhealthyPodEvictionPolicy != nil {
|
||||
in, out := &in.UnhealthyPodEvictionPolicy, &out.UnhealthyPodEvictionPolicy
|
||||
*out = new(UnhealthyPodEvictionPolicyType)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,8 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxUnavailable": "maxUnavailableValue"
|
||||
"maxUnavailable": "maxUnavailableValue",
|
||||
"unhealthyPodEvictionPolicy": "unhealthyPodEvictionPolicyValue"
|
||||
},
|
||||
"status": {
|
||||
"observedGeneration": 1,
|
||||
|
Binary file not shown.
@ -43,6 +43,7 @@ spec:
|
||||
- valuesValue
|
||||
matchLabels:
|
||||
matchLabelsKey: matchLabelsValue
|
||||
unhealthyPodEvictionPolicy: unhealthyPodEvictionPolicyValue
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2004-01-01T01:01:01Z"
|
||||
|
@ -59,7 +59,8 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"maxUnavailable": "maxUnavailableValue"
|
||||
"maxUnavailable": "maxUnavailableValue",
|
||||
"unhealthyPodEvictionPolicy": "unhealthyPodEvictionPolicyValue"
|
||||
},
|
||||
"status": {
|
||||
"observedGeneration": 1,
|
||||
|
Binary file not shown.
@ -43,6 +43,7 @@ spec:
|
||||
- valuesValue
|
||||
matchLabels:
|
||||
matchLabelsKey: matchLabelsValue
|
||||
unhealthyPodEvictionPolicy: unhealthyPodEvictionPolicyValue
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2004-01-01T01:01:01Z"
|
||||
|
@ -10610,6 +10610,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
||||
- name: selector
|
||||
type:
|
||||
namedType: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector
|
||||
- name: unhealthyPodEvictionPolicy
|
||||
type:
|
||||
scalar: string
|
||||
- name: io.k8s.api.policy.v1.PodDisruptionBudgetStatus
|
||||
map:
|
||||
fields:
|
||||
@ -10751,6 +10754,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
||||
- name: selector
|
||||
type:
|
||||
namedType: io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector
|
||||
- name: unhealthyPodEvictionPolicy
|
||||
type:
|
||||
scalar: string
|
||||
- name: io.k8s.api.policy.v1beta1.PodDisruptionBudgetStatus
|
||||
map:
|
||||
fields:
|
||||
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
policyv1 "k8s.io/api/policy/v1"
|
||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||
)
|
||||
@ -29,6 +30,7 @@ type PodDisruptionBudgetSpecApplyConfiguration struct {
|
||||
MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty"`
|
||||
Selector *v1.LabelSelectorApplyConfiguration `json:"selector,omitempty"`
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
|
||||
UnhealthyPodEvictionPolicy *policyv1.UnhealthyPodEvictionPolicyType `json:"unhealthyPodEvictionPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// PodDisruptionBudgetSpecApplyConfiguration constructs an declarative configuration of the PodDisruptionBudgetSpec type for use with
|
||||
@ -60,3 +62,11 @@ func (b *PodDisruptionBudgetSpecApplyConfiguration) WithMaxUnavailable(value int
|
||||
b.MaxUnavailable = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithUnhealthyPodEvictionPolicy sets the UnhealthyPodEvictionPolicy 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 UnhealthyPodEvictionPolicy field is set to the value of the last call.
|
||||
func (b *PodDisruptionBudgetSpecApplyConfiguration) WithUnhealthyPodEvictionPolicy(value policyv1.UnhealthyPodEvictionPolicyType) *PodDisruptionBudgetSpecApplyConfiguration {
|
||||
b.UnhealthyPodEvictionPolicy = &value
|
||||
return b
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/policy/v1beta1"
|
||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||
)
|
||||
@ -29,6 +30,7 @@ type PodDisruptionBudgetSpecApplyConfiguration struct {
|
||||
MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty"`
|
||||
Selector *v1.LabelSelectorApplyConfiguration `json:"selector,omitempty"`
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
|
||||
UnhealthyPodEvictionPolicy *v1beta1.UnhealthyPodEvictionPolicyType `json:"unhealthyPodEvictionPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// PodDisruptionBudgetSpecApplyConfiguration constructs an declarative configuration of the PodDisruptionBudgetSpec type for use with
|
||||
@ -60,3 +62,11 @@ func (b *PodDisruptionBudgetSpecApplyConfiguration) WithMaxUnavailable(value int
|
||||
b.MaxUnavailable = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithUnhealthyPodEvictionPolicy sets the UnhealthyPodEvictionPolicy 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 UnhealthyPodEvictionPolicy field is set to the value of the last call.
|
||||
func (b *PodDisruptionBudgetSpecApplyConfiguration) WithUnhealthyPodEvictionPolicy(value v1beta1.UnhealthyPodEvictionPolicyType) *PodDisruptionBudgetSpecApplyConfiguration {
|
||||
b.UnhealthyPodEvictionPolicy = &value
|
||||
return b
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func TestConcurrentEvictionRequests(t *testing.T) {
|
||||
t.Errorf("Failed to create PodDisruptionBudget: %v", err)
|
||||
}
|
||||
|
||||
waitPDBStable(t, clientSet, numOfEvictions, ns.Name, pdb.Name)
|
||||
waitPDBStable(t, clientSet, ns.Name, pdb.Name, numOfEvictions)
|
||||
|
||||
var numberPodsEvicted uint32
|
||||
errCh := make(chan error, 3*numOfEvictions)
|
||||
@ -212,7 +212,7 @@ func TestTerminalPodEviction(t *testing.T) {
|
||||
t.Errorf("Failed to create PodDisruptionBudget: %v", err)
|
||||
}
|
||||
|
||||
waitPDBStable(t, clientSet, 1, ns.Name, pdb.Name)
|
||||
waitPDBStable(t, clientSet, ns.Name, pdb.Name, 1)
|
||||
|
||||
pdbList, err := clientSet.PolicyV1().PodDisruptionBudgets(ns.Name).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
@ -394,13 +394,7 @@ func TestEvictionWithFinalizers(t *testing.T) {
|
||||
|
||||
eviction := newV1Eviction(ns.Name, pod.Name, deleteOption)
|
||||
|
||||
err := wait.PollImmediate(5*time.Second, 60*time.Second, func() (bool, error) {
|
||||
e := clientSet.PolicyV1().Evictions(ns.Name).Evict(ctx, eviction)
|
||||
if e != nil {
|
||||
return false, e
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
err := clientSet.PolicyV1().Evictions(ns.Name).Evict(ctx, eviction)
|
||||
if err != nil {
|
||||
t.Fatalf("Eviction of pod failed %v", err)
|
||||
}
|
||||
@ -419,6 +413,95 @@ func TestEvictionWithFinalizers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestEvictionWithUnhealthyPodEvictionPolicy tests eviction with a PDB that has a UnhealthyPodEvictionPolicy
|
||||
func TestEvictionWithUnhealthyPodEvictionPolicy(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
enableUnhealthyPodEvictionPolicy bool
|
||||
unhealthyPodEvictionPolicy *policyv1.UnhealthyPodEvictionPolicyType
|
||||
isPodReady bool
|
||||
}{
|
||||
"UnhealthyPodEvictionPolicy disabled and policy not set": {
|
||||
enableUnhealthyPodEvictionPolicy: false,
|
||||
unhealthyPodEvictionPolicy: nil,
|
||||
isPodReady: true,
|
||||
},
|
||||
"UnhealthyPodEvictionPolicy enabled but policy not set": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: nil,
|
||||
isPodReady: true,
|
||||
},
|
||||
"UnhealthyPodEvictionPolicy enabled but policy set to IfHealthyBudget with ready pod": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policyv1.IfHealthyBudget),
|
||||
isPodReady: true,
|
||||
},
|
||||
"UnhealthyPodEvictionPolicy enabled but policy set to AlwaysAllow with ready pod": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policyv1.AlwaysAllow),
|
||||
isPodReady: true,
|
||||
},
|
||||
"UnhealthyPodEvictionPolicy enabled but policy set to AlwaysAllow with unready pod": {
|
||||
enableUnhealthyPodEvictionPolicy: true,
|
||||
unhealthyPodEvictionPolicy: unhealthyPolicyPtr(policyv1.AlwaysAllow),
|
||||
isPodReady: false,
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.PDBUnhealthyPodEvictionPolicy, tc.enableUnhealthyPodEvictionPolicy)()
|
||||
closeFn, rm, informers, _, clientSet := rmSetup(t)
|
||||
defer closeFn()
|
||||
|
||||
ns := framework.CreateNamespaceOrDie(clientSet, "eviction-with-pdb-pod-healthy-policy", t)
|
||||
defer framework.DeleteNamespaceOrDie(clientSet, ns, t)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
informers.Start(ctx.Done())
|
||||
go rm.Run(ctx)
|
||||
|
||||
pod := newPod("pod")
|
||||
if _, err := clientSet.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
|
||||
t.Errorf("Failed to create pod: %v", err)
|
||||
}
|
||||
|
||||
pod.Status.Phase = v1.PodRunning
|
||||
if tc.isPodReady {
|
||||
addPodConditionReady(pod)
|
||||
}
|
||||
|
||||
if _, err := clientSet.CoreV1().Pods(ns.Name).UpdateStatus(ctx, pod, metav1.UpdateOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 1, v1.PodRunning)
|
||||
|
||||
pdb := newPDB()
|
||||
pdb.Spec.UnhealthyPodEvictionPolicy = tc.unhealthyPodEvictionPolicy
|
||||
if _, err := clientSet.PolicyV1().PodDisruptionBudgets(ns.Name).Create(context.TODO(), pdb, metav1.CreateOptions{}); err != nil {
|
||||
t.Errorf("Failed to create PodDisruptionBudget: %v", err)
|
||||
}
|
||||
|
||||
if tc.isPodReady {
|
||||
waitPDBStable(t, clientSet, ns.Name, pdb.Name, 1)
|
||||
} else {
|
||||
waitPDB(t, clientSet, ns.Name, pdb.Name, func(pdb *policyv1.PodDisruptionBudget) bool {
|
||||
return pdb.Status.ExpectedPods == 1
|
||||
})
|
||||
}
|
||||
deleteOption := metav1.DeleteOptions{}
|
||||
eviction := newV1Eviction(ns.Name, pod.Name, deleteOption)
|
||||
err := clientSet.PolicyV1().Evictions(ns.Name).Evict(ctx, eviction)
|
||||
if err != nil {
|
||||
t.Fatalf("Eviction of pod failed %v", err)
|
||||
}
|
||||
|
||||
waitToObservePods(t, informers.Core().V1().Pods().Informer(), 0, v1.PodRunning)
|
||||
waitPDBStable(t, clientSet, ns.Name, pdb.Name, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newPod(podName string) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -533,17 +616,24 @@ func waitToObservePods(t *testing.T, podInformer cache.SharedIndexInformer, podN
|
||||
}
|
||||
}
|
||||
|
||||
func waitPDBStable(t *testing.T, clientSet clientset.Interface, podNum int32, ns, pdbName string) {
|
||||
func waitPDBStable(t *testing.T, clientSet clientset.Interface, ns, pdbName string, podNum int32) {
|
||||
waitPDB(t, clientSet, ns, pdbName, func(pdb *policyv1.PodDisruptionBudget) bool {
|
||||
return pdb.Status.CurrentHealthy == podNum
|
||||
})
|
||||
}
|
||||
|
||||
func waitPDB(t *testing.T, clientSet clientset.Interface, ns, pdbName string, condition func(budget *policyv1.PodDisruptionBudget) bool) {
|
||||
if err := wait.PollImmediate(2*time.Second, 60*time.Second, func() (bool, error) {
|
||||
pdb, err := clientSet.PolicyV1().PodDisruptionBudgets(ns).Get(context.TODO(), pdbName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pdb.Status.CurrentHealthy != podNum {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
return condition(pdb), nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func unhealthyPolicyPtr(unhealthyPodEvictionPolicy policyv1.UnhealthyPodEvictionPolicyType) *policyv1.UnhealthyPodEvictionPolicyType {
|
||||
return &unhealthyPodEvictionPolicy
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user