mirror of https://github.com/openkruise/kruise.git
add pub interface GetPodsForPub (#758)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
This commit is contained in:
parent
e4956e650b
commit
c8f0a54c5d
|
|
@ -79,7 +79,7 @@ type PodUnavailableBudgetStatus struct {
|
|||
// DesiredAvailable minimum desired number of available pods
|
||||
DesiredAvailable int32 `json:"desiredAvailable"`
|
||||
|
||||
// TotalReplicas total number of pods counted by this budget
|
||||
// TotalReplicas total number of pods counted by this unavailable budget
|
||||
TotalReplicas int32 `json:"totalReplicas"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ spec:
|
|||
format: int64
|
||||
type: integer
|
||||
totalReplicas:
|
||||
description: TotalReplicas total number of pods counted by this budget
|
||||
description: TotalReplicas total number of pods counted by this unavailable budget
|
||||
format: int32
|
||||
type: integer
|
||||
unavailableAllowed:
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ package pubcontrol
|
|||
|
||||
import (
|
||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type PubControl interface {
|
||||
|
|
@ -32,12 +33,17 @@ type PubControl interface {
|
|||
IsPodReady(pod *corev1.Pod) bool
|
||||
// IsPodStateConsistent indicates whether pod.spec and pod.status are consistent after updating containers
|
||||
IsPodStateConsistent(pod *corev1.Pod) bool
|
||||
// GetPodsForPub returns Pods protected by the pub object.
|
||||
// return two parameters
|
||||
// 1. podList
|
||||
// 2. expectedCount, the default is workload.Replicas
|
||||
GetPodsForPub() ([]*corev1.Pod, int32, error)
|
||||
|
||||
// webhook
|
||||
// determine if this change to pod might cause unavailability
|
||||
IsPodUnavailableChanged(oldPod, newPod *corev1.Pod) bool
|
||||
}
|
||||
|
||||
func NewPubControl(pub *policyv1alpha1.PodUnavailableBudget) PubControl {
|
||||
return &commonControl{PodUnavailableBudget: pub}
|
||||
func NewPubControl(pub *policyv1alpha1.PodUnavailableBudget, controllerFinder *controllerfinder.ControllerFinder, client client.Client) PubControl {
|
||||
return &commonControl{PodUnavailableBudget: pub, controllerFinder: controllerFinder, Client: client}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,21 +17,26 @@ limitations under the License.
|
|||
package pubcontrol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
"github.com/openkruise/kruise/pkg/control/sidecarcontrol"
|
||||
"github.com/openkruise/kruise/pkg/util"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/klog/v2"
|
||||
kubecontroller "k8s.io/kubernetes/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type commonControl struct {
|
||||
client.Client
|
||||
*policyv1alpha1.PodUnavailableBudget
|
||||
controllerFinder *controllerfinder.ControllerFinder
|
||||
}
|
||||
|
||||
func (c *commonControl) GetPodUnavailableBudget() *policyv1alpha1.PodUnavailableBudget {
|
||||
|
|
@ -58,6 +63,49 @@ func (c *commonControl) IsPodUnavailableChanged(oldPod, newPod *corev1.Pod) bool
|
|||
return false
|
||||
}
|
||||
|
||||
// GetPodsForPub returns Pods protected by the pub object.
|
||||
// return two parameters
|
||||
// 1. podList
|
||||
// 2. expectedCount, the default is workload.Replicas
|
||||
func (c *commonControl) GetPodsForPub() ([]*corev1.Pod, int32, error) {
|
||||
pub := c.GetPodUnavailableBudget()
|
||||
// if targetReference isn't nil, priority to take effect
|
||||
var listOptions *client.ListOptions
|
||||
if pub.Spec.TargetReference != nil {
|
||||
ref := pub.Spec.TargetReference
|
||||
matchedPods, expectedCount, err := c.controllerFinder.GetPodsForRef(ref.APIVersion, ref.Kind, ref.Name, pub.Namespace, true)
|
||||
return matchedPods, expectedCount, err
|
||||
} else if pub.Spec.Selector == nil {
|
||||
klog.Warningf("pub(%s/%s) spec.Selector cannot be empty", pub.Namespace, pub.Name)
|
||||
return nil, 0, nil
|
||||
}
|
||||
// get pods for selector
|
||||
labelSelector, err := util.GetFastLabelSelector(pub.Spec.Selector)
|
||||
if err != nil {
|
||||
klog.Warningf("pub(%s/%s) GetFastLabelSelector failed: %s", pub.Namespace, pub.Name, err.Error())
|
||||
return nil, 0, nil
|
||||
}
|
||||
listOptions = &client.ListOptions{Namespace: pub.Namespace, LabelSelector: labelSelector}
|
||||
podList := &corev1.PodList{}
|
||||
if err := c.List(context.TODO(), podList, listOptions); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
matchedPods := make([]*corev1.Pod, 0, len(podList.Items))
|
||||
for i := range podList.Items {
|
||||
pod := &podList.Items[i]
|
||||
if kubecontroller.IsPodActive(pod) {
|
||||
matchedPods = append(matchedPods, pod)
|
||||
}
|
||||
}
|
||||
expectedCount, err := c.controllerFinder.GetExpectedScaleForPods(matchedPods)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return matchedPods, expectedCount, nil
|
||||
}
|
||||
|
||||
func (c *commonControl) IsPodStateConsistent(pod *corev1.Pod) bool {
|
||||
// if all container image is digest format
|
||||
// by comparing status.containers[x].ImageID with spec.container[x].Image can determine whether pod is consistent
|
||||
|
|
|
|||
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
Copyright 2021 The Kruise Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package pubcontrol
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
)
|
||||
|
||||
func init() {
|
||||
scheme = runtime.NewScheme()
|
||||
_ = policyv1alpha1.AddToScheme(scheme)
|
||||
_ = corev1.AddToScheme(scheme)
|
||||
_ = apps.AddToScheme(scheme)
|
||||
}
|
||||
|
||||
var (
|
||||
scheme *runtime.Scheme
|
||||
|
||||
pubDemo = policyv1alpha1.PodUnavailableBudget{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: policyv1alpha1.GroupVersion.String(),
|
||||
Kind: "PodUnavailableBudget",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "pub-test",
|
||||
},
|
||||
Spec: policyv1alpha1.PodUnavailableBudgetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "30%",
|
||||
},
|
||||
},
|
||||
Status: policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailablePods: map[string]metav1.Time{},
|
||||
DisruptedPods: map[string]metav1.Time{},
|
||||
},
|
||||
}
|
||||
|
||||
podDemo = &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-pod",
|
||||
Namespace: "default",
|
||||
Labels: map[string]string{"app": "nginx", "pub-controller": "true"},
|
||||
Annotations: map[string]string{},
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "ReplicaSet",
|
||||
Name: "nginx",
|
||||
UID: types.UID("606132e0-85ef-460a-8cf5-cd8f915a8cc3"),
|
||||
Controller: utilpointer.BoolPtr(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: "nginx:v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: corev1.PodStatus{
|
||||
Phase: corev1.PodRunning,
|
||||
Conditions: []corev1.PodCondition{
|
||||
{
|
||||
Type: corev1.PodReady,
|
||||
Status: corev1.ConditionTrue,
|
||||
},
|
||||
},
|
||||
ContainerStatuses: []corev1.ContainerStatus{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: "nginx:v1",
|
||||
ImageID: "nginx@sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d",
|
||||
Ready: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
deploymentDemo = &apps.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "nginx",
|
||||
Namespace: "default",
|
||||
UID: types.UID("f6d5b184-d82f-461c-a432-fbd59e2f0379"),
|
||||
},
|
||||
Spec: apps.DeploymentSpec{
|
||||
Replicas: utilpointer.Int32Ptr(10),
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
replicaSetDemo = &apps.ReplicaSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ReplicaSet",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "nginx",
|
||||
Namespace: "default",
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
Name: "nginx",
|
||||
UID: types.UID("f6d5b184-d82f-461c-a432-fbd59e2f0379"),
|
||||
Controller: utilpointer.BoolPtr(true),
|
||||
},
|
||||
},
|
||||
UID: types.UID("606132e0-85ef-460a-8cf5-cd8f915a8cc3"),
|
||||
Labels: map[string]string{
|
||||
"app": "nginx",
|
||||
},
|
||||
},
|
||||
Spec: apps.ReplicaSetSpec{
|
||||
Replicas: utilpointer.Int32Ptr(10),
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestGetPodUnavailableBudgetForPod(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
getPod func() *corev1.Pod
|
||||
getDeployment func() *apps.Deployment
|
||||
getReplicaSet func() *apps.ReplicaSet
|
||||
getPub func() *policyv1alpha1.PodUnavailableBudget
|
||||
matchedPub bool
|
||||
}{
|
||||
{
|
||||
name: "matched pub targetRef deployment",
|
||||
getPod: func() *corev1.Pod {
|
||||
pod := podDemo.DeepCopy()
|
||||
return pod
|
||||
},
|
||||
getDeployment: func() *apps.Deployment {
|
||||
dep := deploymentDemo.DeepCopy()
|
||||
return dep
|
||||
},
|
||||
getReplicaSet: func() *apps.ReplicaSet {
|
||||
rep := replicaSetDemo.DeepCopy()
|
||||
return rep
|
||||
},
|
||||
getPub: func() *policyv1alpha1.PodUnavailableBudget {
|
||||
pub := pubDemo.DeepCopy()
|
||||
pub.Spec.Selector = nil
|
||||
pub.Spec.TargetReference = &policyv1alpha1.TargetReference{
|
||||
Name: deploymentDemo.Name,
|
||||
Kind: deploymentDemo.Kind,
|
||||
APIVersion: deploymentDemo.APIVersion,
|
||||
}
|
||||
return pub
|
||||
},
|
||||
matchedPub: true,
|
||||
},
|
||||
{
|
||||
name: "no matched pub targetRef deployment, for unequal name",
|
||||
getPod: func() *corev1.Pod {
|
||||
pod := podDemo.DeepCopy()
|
||||
return pod
|
||||
},
|
||||
getDeployment: func() *apps.Deployment {
|
||||
dep := deploymentDemo.DeepCopy()
|
||||
return dep
|
||||
},
|
||||
getReplicaSet: func() *apps.ReplicaSet {
|
||||
rep := replicaSetDemo.DeepCopy()
|
||||
return rep
|
||||
},
|
||||
getPub: func() *policyv1alpha1.PodUnavailableBudget {
|
||||
pub := pubDemo.DeepCopy()
|
||||
pub.Spec.Selector = nil
|
||||
pub.Spec.TargetReference = &policyv1alpha1.TargetReference{
|
||||
Name: "no-deployment",
|
||||
Kind: deploymentDemo.Kind,
|
||||
APIVersion: deploymentDemo.APIVersion,
|
||||
}
|
||||
return pub
|
||||
},
|
||||
matchedPub: false,
|
||||
},
|
||||
{
|
||||
name: "no matched pub targetRef deployment, for unequal ns",
|
||||
getPod: func() *corev1.Pod {
|
||||
pod := podDemo.DeepCopy()
|
||||
return pod
|
||||
},
|
||||
getDeployment: func() *apps.Deployment {
|
||||
dep := deploymentDemo.DeepCopy()
|
||||
return dep
|
||||
},
|
||||
getReplicaSet: func() *apps.ReplicaSet {
|
||||
rep := replicaSetDemo.DeepCopy()
|
||||
return rep
|
||||
},
|
||||
getPub: func() *policyv1alpha1.PodUnavailableBudget {
|
||||
pub := pubDemo.DeepCopy()
|
||||
pub.Namespace = "no-ns"
|
||||
pub.Spec.Selector = nil
|
||||
pub.Spec.TargetReference = &policyv1alpha1.TargetReference{
|
||||
Name: deploymentDemo.Name,
|
||||
Kind: deploymentDemo.Kind,
|
||||
APIVersion: deploymentDemo.APIVersion,
|
||||
}
|
||||
return pub
|
||||
},
|
||||
matchedPub: false,
|
||||
},
|
||||
{
|
||||
name: "matched pub selector",
|
||||
getPod: func() *corev1.Pod {
|
||||
pod := podDemo.DeepCopy()
|
||||
return pod
|
||||
},
|
||||
getDeployment: func() *apps.Deployment {
|
||||
dep := deploymentDemo.DeepCopy()
|
||||
return dep
|
||||
},
|
||||
getReplicaSet: func() *apps.ReplicaSet {
|
||||
rep := replicaSetDemo.DeepCopy()
|
||||
return rep
|
||||
},
|
||||
getPub: func() *policyv1alpha1.PodUnavailableBudget {
|
||||
pub := pubDemo.DeepCopy()
|
||||
return pub
|
||||
},
|
||||
matchedPub: true,
|
||||
},
|
||||
{
|
||||
name: "no match pub selector",
|
||||
getPod: func() *corev1.Pod {
|
||||
pod := podDemo.DeepCopy()
|
||||
return pod
|
||||
},
|
||||
getDeployment: func() *apps.Deployment {
|
||||
dep := deploymentDemo.DeepCopy()
|
||||
return dep
|
||||
},
|
||||
getReplicaSet: func() *apps.ReplicaSet {
|
||||
rep := replicaSetDemo.DeepCopy()
|
||||
return rep
|
||||
},
|
||||
getPub: func() *policyv1alpha1.PodUnavailableBudget {
|
||||
pub := pubDemo.DeepCopy()
|
||||
pub.Spec.Selector = &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"pub-controller": "false",
|
||||
},
|
||||
}
|
||||
return pub
|
||||
},
|
||||
matchedPub: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, cs := range cases {
|
||||
t.Run(cs.name, func(t *testing.T) {
|
||||
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cs.getDeployment(), cs.getReplicaSet(), cs.getPub()).Build()
|
||||
controllerFinder := controllerfinder.NewControllerFinder(fakeClient)
|
||||
pod := cs.getPod()
|
||||
pub, err := GetPodUnavailableBudgetForPod(fakeClient, controllerFinder, pod)
|
||||
if err != nil {
|
||||
t.Fatalf("GetPodUnavailableBudgetForPod failed: %s", err.Error())
|
||||
}
|
||||
if cs.matchedPub && pub == nil {
|
||||
t.Fatalf("GetPodUnavailableBudgetForPod failed")
|
||||
}
|
||||
if !cs.matchedPub && pub != nil {
|
||||
t.Fatalf("GetPodUnavailableBudgetForPod failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
|
||||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
|
|
@ -48,6 +49,7 @@ type realControl struct {
|
|||
lifecycleControl lifecycle.Interface
|
||||
inplaceControl inplaceupdate.Interface
|
||||
recorder record.EventRecorder
|
||||
controllerFinder *controllerfinder.ControllerFinder
|
||||
}
|
||||
|
||||
func New(c client.Client, recorder record.EventRecorder) Interface {
|
||||
|
|
@ -56,5 +58,6 @@ func New(c client.Client, recorder record.EventRecorder) Interface {
|
|||
inplaceControl: inplaceupdate.New(c, clonesetutils.RevisionAdapterImpl),
|
||||
lifecycleControl: lifecycle.New(c),
|
||||
recorder: recorder,
|
||||
controllerFinder: controllerfinder.NewControllerFinder(c),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import (
|
|||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
||||
"github.com/openkruise/kruise/pkg/features"
|
||||
"github.com/openkruise/kruise/pkg/util"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
|
||||
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||
|
|
@ -122,7 +121,7 @@ func (c *realControl) Update(cs *appsv1alpha1.CloneSet,
|
|||
var pub *policyv1alpha1.PodUnavailableBudget
|
||||
var err error
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.PodUnavailableBudgetUpdateGate) && len(waitUpdateIndexes) > 0 {
|
||||
pub, err = pubcontrol.GetPodUnavailableBudgetForPod(c.Client, controllerfinder.NewControllerFinder(c.Client), pods[waitUpdateIndexes[0]])
|
||||
pub, err = pubcontrol.GetPodUnavailableBudgetForPod(c.Client, c.controllerFinder, pods[waitUpdateIndexes[0]])
|
||||
if err != nil {
|
||||
return requeueDuration.Get(), err
|
||||
}
|
||||
|
|
@ -132,7 +131,7 @@ func (c *realControl) Update(cs *appsv1alpha1.CloneSet,
|
|||
pod := pods[idx]
|
||||
// Determine the pub before updating the pod
|
||||
if pub != nil {
|
||||
allowed, _, err := pubcontrol.PodUnavailableBudgetValidatePod(c.Client, pod, pubcontrol.NewPubControl(pub), pubcontrol.UpdateOperation, false)
|
||||
allowed, _, err := pubcontrol.PodUnavailableBudgetValidatePod(c.Client, pod, pubcontrol.NewPubControl(pub, c.controllerFinder, c.Client), pubcontrol.UpdateOperation, false)
|
||||
if err != nil {
|
||||
return requeueDuration.Get(), err
|
||||
// pub check does not pass, try again in seconds
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
clonesetcore "github.com/openkruise/kruise/pkg/controller/cloneset/core"
|
||||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
||||
"github.com/openkruise/kruise/pkg/util"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
|
|
@ -573,6 +574,7 @@ func TestUpdate(t *testing.T) {
|
|||
lifecycle.NewForTest(fakeClient),
|
||||
inplaceupdate.NewForTest(fakeClient, clonesetutils.RevisionAdapterImpl, func() metav1.Time { return now }),
|
||||
record.NewFakeRecorder(10),
|
||||
controllerfinder.NewControllerFinder(fakeClient),
|
||||
}
|
||||
currentRevision := mc.updateRevision
|
||||
if len(mc.revisions) > 0 {
|
||||
|
|
|
|||
|
|
@ -181,7 +181,8 @@ func (r *ReconcilePodUnavailableBudget) Reconcile(_ context.Context, req ctrl.Re
|
|||
}
|
||||
|
||||
func (r *ReconcilePodUnavailableBudget) syncPodUnavailableBudget(pub *policyv1alpha1.PodUnavailableBudget) (*time.Time, error) {
|
||||
pods, err := r.getPodsForPub(pub)
|
||||
control := pubcontrol.NewPubControl(pub, r.controllerFinder, r.Client)
|
||||
pods, expectedCount, err := control.GetPodsForPub()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -189,8 +190,8 @@ func (r *ReconcilePodUnavailableBudget) syncPodUnavailableBudget(pub *policyv1al
|
|||
r.recorder.Eventf(pub, corev1.EventTypeNormal, "NoPods", "No matching pods found")
|
||||
}
|
||||
|
||||
klog.V(3).Infof("pub(%s.%s) controller len(%d) pods", pub.Namespace, pub.Name, len(pods))
|
||||
expectedCount, desiredAvailable, err := r.getExpectedPodCount(pub, pods)
|
||||
klog.V(3).Infof("pub(%s.%s) controller pods(%d) expectedCount(%d)", pub.Namespace, pub.Name, len(pods), expectedCount)
|
||||
desiredAvailable, err := r.getDesiredAvailableForPub(pub, expectedCount)
|
||||
if err != nil {
|
||||
r.recorder.Eventf(pub, corev1.EventTypeWarning, "CalculateExpectedPodCountFailed", "Failed to calculate the number of expected pods: %v", err)
|
||||
return nil, err
|
||||
|
|
@ -200,7 +201,6 @@ func (r *ReconcilePodUnavailableBudget) syncPodUnavailableBudget(pub *policyv1al
|
|||
var conflictTimes int
|
||||
var costOfGet, costOfUpdate time.Duration
|
||||
|
||||
control := pubcontrol.NewPubControl(pub)
|
||||
currentTime := time.Now()
|
||||
var pubClone *policyv1alpha1.PodUnavailableBudget
|
||||
refresh := false
|
||||
|
|
@ -328,14 +328,10 @@ func (r *ReconcilePodUnavailableBudget) getPodsForPub(pub *policyv1alpha1.PodUna
|
|||
return matchedPods, nil
|
||||
}
|
||||
|
||||
func (r *ReconcilePodUnavailableBudget) getExpectedPodCount(pub *policyv1alpha1.PodUnavailableBudget, pods []*corev1.Pod) (expectedCount, desiredAvailable int32, err error) {
|
||||
func (r *ReconcilePodUnavailableBudget) getDesiredAvailableForPub(pub *policyv1alpha1.PodUnavailableBudget, expectedCount int32) (desiredAvailable int32, err error) {
|
||||
if pub.Spec.MaxUnavailable != nil {
|
||||
expectedCount, err = r.getExpectedScale(pub, pods)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var maxUnavailable int
|
||||
maxUnavailable, err = intstr.GetValueFromIntOrPercent(pub.Spec.MaxUnavailable, int(expectedCount), false)
|
||||
maxUnavailable, err = intstr.GetScaledValueFromIntOrPercent(pub.Spec.MaxUnavailable, int(expectedCount), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -347,15 +343,9 @@ func (r *ReconcilePodUnavailableBudget) getExpectedPodCount(pub *policyv1alpha1.
|
|||
} else if pub.Spec.MinAvailable != nil {
|
||||
if pub.Spec.MinAvailable.Type == intstr.Int {
|
||||
desiredAvailable = pub.Spec.MinAvailable.IntVal
|
||||
expectedCount = int32(len(pods))
|
||||
} else if pub.Spec.MinAvailable.Type == intstr.String {
|
||||
expectedCount, err = r.getExpectedScale(pub, pods)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var minAvailable int
|
||||
minAvailable, err = intstr.GetValueFromIntOrPercent(pub.Spec.MinAvailable, int(expectedCount), true)
|
||||
minAvailable, err = intstr.GetScaledValueFromIntOrPercent(pub.Spec.MinAvailable, int(expectedCount), true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -457,7 +447,7 @@ func (r *ReconcilePodUnavailableBudget) buildDisruptedAndUnavailablePods(pods []
|
|||
// handle unavailable pods which have been in-updated specification
|
||||
unavailableTime, found := unavailablePods[pod.Name]
|
||||
if found {
|
||||
// in case of informer cache latency, after 5 seconds to remove it
|
||||
// in case of informer cache latency, after 10 seconds to remove it
|
||||
expectedUpdate := unavailableTime.Time.Add(UpdatedDelayCheckTime)
|
||||
if expectedUpdate.Before(currentTime) {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import (
|
|||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
"github.com/openkruise/kruise/pkg/util"
|
||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -425,7 +424,7 @@ func TestPubReconcile(t *testing.T) {
|
|||
UnavailableAllowed: 0,
|
||||
CurrentAvailable: 5,
|
||||
DesiredAvailable: 100,
|
||||
TotalReplicas: 5,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ func (p *enqueueRequestForPod) updatePod(q workqueue.RateLimitingInterface, old,
|
|||
oldPub, _ := pubcontrol.GetPodUnavailableBudgetForPod(p.client, p.controllerFinder, oldPod)
|
||||
newPub, _ := pubcontrol.GetPodUnavailableBudgetForPod(p.client, p.controllerFinder, newPod)
|
||||
if oldPub != nil && newPub != nil && oldPub.Name == newPub.Name {
|
||||
control := pubcontrol.NewPubControl(newPub)
|
||||
control := pubcontrol.NewPubControl(newPub, p.controllerFinder, p.client)
|
||||
if isReconcile, enqueueDelayTime := isPodAvailableChanged(oldPod, newPod, newPub, control); isReconcile {
|
||||
q.AddAfter(reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
|
|
@ -124,7 +124,7 @@ func (p *enqueueRequestForPod) updatePod(q workqueue.RateLimitingInterface, old,
|
|||
if pub == nil {
|
||||
return
|
||||
}
|
||||
control := pubcontrol.NewPubControl(pub)
|
||||
control := pubcontrol.NewPubControl(pub, p.controllerFinder, p.client)
|
||||
if isReconcile, enqueueDelayTime := isPodAvailableChanged(oldPod, newPod, pub, control); isReconcile {
|
||||
q.AddAfter(reconcile.Request{
|
||||
NamespacedName: types.NamespacedName{
|
||||
|
|
|
|||
|
|
@ -68,6 +68,39 @@ func NewControllerFinder(c client.Client) *ControllerFinder {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *ControllerFinder) GetExpectedScaleForPods(pods []*corev1.Pod) (int32, error) {
|
||||
// 1. Find the controller for each pod. If any pod has 0 controllers,
|
||||
// that's an error. With ControllerRef, a pod can only have 1 controller.
|
||||
// A mapping from controllers to their scale.
|
||||
controllerScale := map[types.UID]int32{}
|
||||
for _, pod := range pods {
|
||||
ref := metav1.GetControllerOf(pod)
|
||||
if ref == nil {
|
||||
continue
|
||||
}
|
||||
// If we already know the scale of the controller there is no need to do anything.
|
||||
if _, found := controllerScale[ref.UID]; found {
|
||||
continue
|
||||
}
|
||||
// Check all the supported controllers to find the desired scale.
|
||||
workload, err := r.GetScaleAndSelectorForRef(ref.APIVersion, ref.Kind, pod.Namespace, ref.Name, ref.UID)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return 0, err
|
||||
}
|
||||
if workload != nil && workload.Metadata.DeletionTimestamp.IsZero() {
|
||||
controllerScale[workload.UID] = workload.Scale
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Add up all the controllers.
|
||||
var expectedCount int32
|
||||
for _, count := range controllerScale {
|
||||
expectedCount += count
|
||||
}
|
||||
|
||||
return expectedCount, nil
|
||||
}
|
||||
|
||||
func (r *ControllerFinder) GetScaleAndSelectorForRef(apiVersion, kind, ns, name string, uid types.UID) (*ScaleAndSelector, error) {
|
||||
targetRef := ControllerReference{
|
||||
APIVersion: apiVersion,
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ func (p *PodCreateHandler) podUnavailableBudgetValidatingPod(ctx context.Context
|
|||
if pub == nil {
|
||||
return true, "", nil
|
||||
}
|
||||
control := pubcontrol.NewPubControl(pub)
|
||||
control := pubcontrol.NewPubControl(pub, p.finders, p.Client)
|
||||
klog.V(3).Infof("validating pod(%s.%s) operation(%s) for pub(%s.%s)", newPod.Namespace, newPod.Name, req.Operation, pub.Namespace, pub.Name)
|
||||
|
||||
// the change will not cause pod unavailability, then pass
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
// volume
|
||||
for _, volume := range cs.exceptVolumes {
|
||||
object := util.GetPodVolume(&pods[0], volume)
|
||||
object := util.GetPodVolume(pods[0], volume)
|
||||
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
||||
}
|
||||
// volumeMounts
|
||||
|
|
@ -318,7 +318,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
// volume
|
||||
for _, volume := range cs.exceptVolumes {
|
||||
object := util.GetPodVolume(&pods[0], volume)
|
||||
object := util.GetPodVolume(pods[0], volume)
|
||||
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
||||
}
|
||||
// volumeMounts
|
||||
|
|
@ -486,13 +486,13 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
origin.Insert(sidecar.Name)
|
||||
}
|
||||
// SidecarSetHashAnnotation = "kruise.io/sidecarset-hash"
|
||||
upgradeSpec1 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashAnnotation, &pod)
|
||||
upgradeSpec1 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashAnnotation, pod)
|
||||
gomega.Expect(upgradeSpec1.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
||||
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
||||
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
||||
// SidecarSetHashWithoutImageAnnotation = "kruise.io/sidecarset-hash-without-image"
|
||||
upgradeSpec2 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashWithoutImageAnnotation, &pod)
|
||||
upgradeSpec2 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashWithoutImageAnnotation, pod)
|
||||
gomega.Expect(upgradeSpec2.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
||||
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
||||
|
|
@ -534,13 +534,13 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
origin.Insert(sidecar.Name)
|
||||
}
|
||||
// SidecarSetHashAnnotation = "kruise.io/sidecarset-hash"
|
||||
upgradeSpec1 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashAnnotation, &pod)
|
||||
upgradeSpec1 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashAnnotation, pod)
|
||||
gomega.Expect(upgradeSpec1.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
||||
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
||||
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
||||
// SidecarSetHashWithoutImageAnnotation = "kruise.io/sidecarset-hash-without-image"
|
||||
upgradeSpec2 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashWithoutImageAnnotation, &pod)
|
||||
upgradeSpec2 := sidecarcontrol.GetPodSidecarSetUpgradeSpecInAnnotations(sidecarSetIn.Name, sidecarcontrol.SidecarSetHashWithoutImageAnnotation, pod)
|
||||
gomega.Expect(upgradeSpec2.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
||||
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
||||
|
|
@ -614,7 +614,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
canaryPod := pods[0]
|
||||
canaryPod.Labels["canary.release"] = "true"
|
||||
tester.UpdatePod(&canaryPod)
|
||||
tester.UpdatePod(canaryPod)
|
||||
time.Sleep(time.Second)
|
||||
// update sidecarSet sidecar container
|
||||
sidecarSetIn.Spec.Containers[0].Image = "busybox:latest"
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
"nginx-sidecar-2": "busybox:latest",
|
||||
}
|
||||
for sidecar, image := range exceptContainer {
|
||||
sidecarContainer := util.GetContainer(sidecar, &pods[0])
|
||||
sidecarContainer := util.GetContainer(sidecar, pods[0])
|
||||
gomega.Expect(sidecarContainer).ShouldNot(gomega.BeNil())
|
||||
gomega.Expect(sidecarContainer.Image).To(gomega.Equal(image))
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
pods, err := tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
podIn := &pods[0]
|
||||
podIn := pods[0]
|
||||
workSidecarContainer := util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
||||
|
|
@ -150,7 +150,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
pods, err = tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
podIn = &pods[0]
|
||||
podIn = pods[0]
|
||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
||||
|
|
@ -175,7 +175,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
pods, err = tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
podIn = &pods[0]
|
||||
podIn = pods[0]
|
||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
||||
|
|
@ -230,7 +230,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
pods, err := tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
podIn := &pods[0]
|
||||
podIn := pods[0]
|
||||
workSidecarContainer := util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
||||
|
|
@ -269,7 +269,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||
// pod[0]
|
||||
podIn1 := &pods[0]
|
||||
podIn1 := pods[0]
|
||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn1)["nginx-sidecar"], podIn1)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
||||
|
|
@ -278,7 +278,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
|||
gomega.Expect(emptySidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||
gomega.Expect(emptySidecarContainer.Image).To(gomega.Equal("busybox:latest"))
|
||||
// pod[1]
|
||||
podIn2 := &pods[1]
|
||||
podIn2 := pods[1]
|
||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn2)["nginx-sidecar"], podIn2)
|
||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
Copyright 2021 The Kruise Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package framework
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
|
||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
kruiseclientset "github.com/openkruise/kruise/pkg/client/clientset/versioned"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
type PodUnavailableBudgetTester struct {
|
||||
c clientset.Interface
|
||||
kc kruiseclientset.Interface
|
||||
}
|
||||
|
||||
func NewPodUnavailableBudgetTester(c clientset.Interface, kc kruiseclientset.Interface) *PodUnavailableBudgetTester {
|
||||
return &PodUnavailableBudgetTester{
|
||||
c: c,
|
||||
kc: kc,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) NewBasePub(namespace string) *policyv1alpha1.PodUnavailableBudget {
|
||||
return &policyv1alpha1.PodUnavailableBudget{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: policyv1alpha1.GroupVersion.String(),
|
||||
Kind: "PodUnavailableBudget",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespace,
|
||||
Name: "busybox-pub",
|
||||
},
|
||||
Spec: policyv1alpha1.PodUnavailableBudgetSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PodUnavailableBudgetTester) NewBaseDeployment(namespace string) *apps.Deployment {
|
||||
return &apps.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "busybox",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: apps.DeploymentSpec{
|
||||
Replicas: utilpointer.Int32Ptr(2),
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "busybox",
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": "busybox",
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "main",
|
||||
Image: "busybox:1.32",
|
||||
Command: []string{"/bin/sh", "-c", "sleep 10000000"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Strategy: apps.DeploymentStrategy{
|
||||
Type: apps.RollingUpdateDeploymentStrategyType,
|
||||
RollingUpdate: &apps.RollingUpdateDeployment{
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "100%",
|
||||
},
|
||||
MaxSurge: &intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PodUnavailableBudgetTester) NewBaseCloneSet(namespace string) *appsv1alpha1.CloneSet {
|
||||
return &appsv1alpha1.CloneSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CloneSet",
|
||||
APIVersion: appsv1alpha1.GroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "busybox",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: appsv1alpha1.CloneSetSpec{
|
||||
Replicas: utilpointer.Int32Ptr(2),
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "busybox",
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"app": "busybox",
|
||||
"pub-controller": "true",
|
||||
},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "main",
|
||||
Image: "busybox:1.32",
|
||||
Command: []string{"/bin/sh", "-c", "sleep 10000000"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UpdateStrategy: appsv1alpha1.CloneSetUpdateStrategy{
|
||||
Type: appsv1alpha1.RecreateCloneSetUpdateStrategyType,
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "100%",
|
||||
},
|
||||
MaxSurge: &intstr.IntOrString{
|
||||
Type: intstr.Int,
|
||||
IntVal: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) CreatePub(pub *policyv1alpha1.PodUnavailableBudget) *policyv1alpha1.PodUnavailableBudget {
|
||||
Logf("create PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name)
|
||||
_, err := t.kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Create(context.TODO(), pub, metav1.CreateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
t.WaitForPubCreated(pub)
|
||||
pub, _ = t.kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
return pub
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) CreateDeployment(deployment *apps.Deployment) {
|
||||
Logf("create deployment(%s.%s)", deployment.Namespace, deployment.Name)
|
||||
_, err := t.c.AppsV1().Deployments(deployment.Namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
t.WaitForDeploymentRunning(deployment)
|
||||
Logf("create deployment(%s.%s) done", deployment.Namespace, deployment.Name)
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) CreateCloneSet(cloneset *appsv1alpha1.CloneSet) *appsv1alpha1.CloneSet {
|
||||
Logf("create CloneSet(%s.%s)", cloneset.Namespace, cloneset.Name)
|
||||
_, err := t.kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Create(context.TODO(), cloneset, metav1.CreateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
t.WaitForCloneSetRunning(cloneset)
|
||||
Logf("create cloneset(%s.%s) done", cloneset.Namespace, cloneset.Name)
|
||||
cloneset, _ = t.kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
return cloneset
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForPubCreated(pub *policyv1alpha1.PodUnavailableBudget) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute,
|
||||
func() (bool, error) {
|
||||
_, err := t.kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for PodUnavailableBudget to enter running: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForDeploymentRunning(deployment *apps.Deployment) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute*5,
|
||||
func() (bool, error) {
|
||||
inner, err := t.c.AppsV1().Deployments(deployment.Namespace).Get(context.TODO(), deployment.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if *inner.Spec.Replicas == inner.Status.ReadyReplicas {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for deployment to enter running: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForCloneSetRunning(cloneset *appsv1alpha1.CloneSet) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute*5,
|
||||
func() (bool, error) {
|
||||
inner, err := t.kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if *inner.Spec.Replicas == inner.Status.ReadyReplicas {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for cloneset to enter running: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForDeploymentMinReadyAndRunning(deployments []*apps.Deployment, minReady int32) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute*5,
|
||||
func() (bool, error) {
|
||||
var readyReplicas int32 = 0
|
||||
completed := 0
|
||||
for _, deployment := range deployments {
|
||||
inner, err := t.c.AppsV1().Deployments(deployment.Namespace).Get(context.TODO(), deployment.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
readyReplicas += inner.Status.ReadyReplicas
|
||||
count := *inner.Spec.Replicas
|
||||
if inner.Status.UpdatedReplicas == count && count == inner.Status.ReadyReplicas && count == inner.Status.Replicas {
|
||||
completed++
|
||||
}
|
||||
}
|
||||
|
||||
if readyReplicas < minReady {
|
||||
return false, fmt.Errorf("deployment ReadyReplicas(%d) < except(%d)", readyReplicas, minReady)
|
||||
}
|
||||
if completed == len(deployments) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for deployment to enter running: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForCloneSetMinReadyAndRunning(cloneSets []*appsv1alpha1.CloneSet, minReady int32) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute*10,
|
||||
func() (bool, error) {
|
||||
var readyReplicas int32 = 0
|
||||
completed := 0
|
||||
for _, cloneSet := range cloneSets {
|
||||
inner, err := t.kc.AppsV1alpha1().CloneSets(cloneSet.Namespace).Get(context.TODO(), cloneSet.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
readyReplicas += inner.Status.ReadyReplicas
|
||||
count := *inner.Spec.Replicas
|
||||
if inner.Status.UpdatedReplicas == count && count == inner.Status.ReadyReplicas && count == inner.Status.Replicas {
|
||||
completed++
|
||||
}
|
||||
}
|
||||
|
||||
if readyReplicas < minReady {
|
||||
return false, fmt.Errorf("deployment ReadyReplicas(%d) < except(%d)", readyReplicas, minReady)
|
||||
}
|
||||
if completed == len(cloneSets) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for cloneSet to enter running: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) DeletePubs(namespace string) {
|
||||
pubList, err := t.kc.PolicyV1alpha1().PodUnavailableBudgets(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
Logf("List sidecarSets failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, pub := range pubList.Items {
|
||||
err := t.kc.PolicyV1alpha1().PodUnavailableBudgets(namespace).Delete(context.TODO(), pub.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
Logf("delete PodUnavailableBudget(%s.%s) failed: %s", pub.Namespace, pub.Name, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) DeleteDeployments(namespace string) {
|
||||
deploymentList, err := t.c.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
Logf("List Deployments failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, deployment := range deploymentList.Items {
|
||||
err := t.c.AppsV1().Deployments(namespace).Delete(context.TODO(), deployment.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
Logf("delete Deployment(%s.%s) failed: %s", deployment.Namespace, deployment.Name, err.Error())
|
||||
continue
|
||||
}
|
||||
t.WaitForDeploymentDeleted(&deployment)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) DeleteCloneSets(namespace string) {
|
||||
objectList, err := t.kc.AppsV1alpha1().CloneSets(namespace).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
Logf("List CloneSets failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, object := range objectList.Items {
|
||||
err := t.kc.AppsV1alpha1().CloneSets(namespace).Delete(context.TODO(), object.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
Logf("delete CloneSet(%s.%s) failed: %s", object.Namespace, object.Name, err.Error())
|
||||
continue
|
||||
}
|
||||
t.WaitForCloneSetDeleted(&object)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForDeploymentDeleted(deployment *apps.Deployment) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute,
|
||||
func() (bool, error) {
|
||||
_, err := t.c.AppsV1().Deployments(deployment.Namespace).Get(context.TODO(), deployment.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for deployment to enter Deleted: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *PodUnavailableBudgetTester) WaitForCloneSetDeleted(cloneset *appsv1alpha1.CloneSet) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute,
|
||||
func() (bool, error) {
|
||||
_, err := t.kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for cloneset to enter Deleted: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SidecarSetTester) WaitForSidecarSetMinReadyAndUpgrade(sidecarSet *appsv1alpha1.SidecarSet, exceptStatus *appsv1alpha1.SidecarSetStatus, minReady int32) {
|
||||
pollErr := wait.PollImmediate(time.Second, time.Minute*5,
|
||||
func() (bool, error) {
|
||||
inner, err := s.kc.AppsV1alpha1().SidecarSets().Get(context.TODO(), sidecarSet.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if minReady > 0 && inner.Status.ReadyPods < minReady {
|
||||
return false, fmt.Errorf("sidecarSet(%s) ReadyReplicas(%d) < except(%d)", sidecarSet.Name, inner.Status.ReadyPods, minReady)
|
||||
}
|
||||
if inner.Status.MatchedPods == exceptStatus.MatchedPods &&
|
||||
inner.Status.UpdatedPods == exceptStatus.UpdatedPods &&
|
||||
inner.Status.UpdatedReadyPods == exceptStatus.UpdatedReadyPods &&
|
||||
inner.Status.ReadyPods == exceptStatus.ReadyPods {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if pollErr != nil {
|
||||
Failf("Failed waiting for sidecarSet to upgrade complete: %v", pollErr)
|
||||
}
|
||||
}
|
||||
|
|
@ -310,7 +310,7 @@ func (s *SidecarSetTester) WaitForSidecarSetDeleted(sidecarSet *appsv1alpha1.Sid
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SidecarSetTester) GetSelectorPods(namespace string, selector *metav1.LabelSelector) ([]corev1.Pod, error) {
|
||||
func (s *SidecarSetTester) GetSelectorPods(namespace string, selector *metav1.LabelSelector) ([]*corev1.Pod, error) {
|
||||
faster, err := util.GetFastLabelSelector(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -319,7 +319,14 @@ func (s *SidecarSetTester) GetSelectorPods(namespace string, selector *metav1.La
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return podList.Items, nil
|
||||
pods := make([]*corev1.Pod, 0)
|
||||
for i := range podList.Items {
|
||||
pod := &podList.Items[i]
|
||||
if pod.DeletionTimestamp.IsZero() {
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
}
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
func (s *SidecarSetTester) NewBaseCloneSet(namespace string) *appsv1alpha1.CloneSet {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,899 @@
|
|||
/*
|
||||
Copyright 2021 The Kruise Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package policy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
"time"
|
||||
|
||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||
kruiseclientset "github.com/openkruise/kruise/pkg/client/clientset/versioned"
|
||||
"github.com/openkruise/kruise/test/e2e/framework"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
apps "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
var _ = SIGDescribe("PodUnavailableBudget", func() {
|
||||
f := framework.NewDefaultFramework("podunavailablebudget")
|
||||
var ns string
|
||||
var c clientset.Interface
|
||||
var kc kruiseclientset.Interface
|
||||
var tester *framework.PodUnavailableBudgetTester
|
||||
var sidecarTester *framework.SidecarSetTester
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
c = f.ClientSet
|
||||
kc = f.KruiseClientSet
|
||||
ns = f.Namespace.Name
|
||||
tester = framework.NewPodUnavailableBudgetTester(c, kc)
|
||||
sidecarTester = framework.NewSidecarSetTester(c, kc)
|
||||
})
|
||||
|
||||
framework.KruiseDescribe("podUnavailableBudget functionality [podUnavailableBudget]", func() {
|
||||
|
||||
ginkgo.AfterEach(func() {
|
||||
if ginkgo.CurrentGinkgoTestDescription().Failed {
|
||||
framework.DumpDebugInfo(c, ns)
|
||||
}
|
||||
framework.Logf("Deleting all PodUnavailableBudgets and Deployments in cluster")
|
||||
tester.DeletePubs(ns)
|
||||
tester.DeleteDeployments(ns)
|
||||
tester.DeleteCloneSets(ns)
|
||||
sidecarTester.DeleteSidecarSets()
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector no matched pods", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create deployment
|
||||
deployment := tester.NewBaseDeployment(ns)
|
||||
deployment.Spec.Selector.MatchLabels["pub-controller"] = "false"
|
||||
deployment.Spec.Template.Labels["pub-controller"] = "false"
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment(%s.%s)", deployment.Namespace, deployment.Name))
|
||||
tester.CreateDeployment(deployment)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 0,
|
||||
CurrentAvailable: 0,
|
||||
TotalReplicas: 0,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
ginkgo.By("PodUnavailableBudget selector no matched pods done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector pods and delete deployment ignore", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create deployment
|
||||
deployment := tester.NewBaseDeployment(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment(%s.%s)", deployment.Namespace, deployment.Name))
|
||||
tester.CreateDeployment(deployment)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := pub.Status.DeepCopy()
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// delete deployment
|
||||
ginkgo.By(fmt.Sprintf("Deleting Deployment(%s.%s)", deployment.Namespace, deployment.Name))
|
||||
err = c.AppsV1().Deployments(deployment.Namespace).Delete(context.TODO(), deployment.Name, metav1.DeleteOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// wait 30 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("waiting 10 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 0,
|
||||
CurrentAvailable: 0,
|
||||
TotalReplicas: 0,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = pub.Status.DeepCopy()
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
pods, err := sidecarTester.GetSelectorPods(deployment.Namespace, deployment.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(pods).To(gomega.HaveLen(0))
|
||||
|
||||
ginkgo.By("PodUnavailableBudget selector pods and delete deployment reject done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget targetReference pods, update failed image and block", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
pub.Spec.Selector = nil
|
||||
pub.Spec.TargetReference = &policyv1alpha1.TargetReference{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
Name: "busybox",
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create deployment
|
||||
deployment := tester.NewBaseDeployment(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment(%s.%s)", deployment.Namespace, deployment.Name))
|
||||
tester.CreateDeployment(deployment)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update failed image
|
||||
ginkgo.By(fmt.Sprintf("update Deployment(%s.%s) failed image(busybox:failed)", deployment.Namespace, deployment.Name))
|
||||
deployment.Spec.Template.Spec.Containers[0].Image = "busybox:failed"
|
||||
_, err = c.AppsV1().Deployments(deployment.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("waiting 20 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second * 20)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 1,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// check now pod
|
||||
pods, err := sidecarTester.GetSelectorPods(deployment.Namespace, deployment.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
noUpdatePods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.Spec.Containers[0].Image == "busybox:failed" || !pod.DeletionTimestamp.IsZero() {
|
||||
continue
|
||||
}
|
||||
noUpdatePods = append(noUpdatePods, *pod)
|
||||
}
|
||||
gomega.Expect(noUpdatePods).To(gomega.HaveLen(1))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update Deployment(%s.%s) success image(busybox:1.33)", deployment.Namespace, deployment.Name))
|
||||
deployment.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
_, err = c.AppsV1().Deployments(deployment.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("waiting 20 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second * 20)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
//check pods
|
||||
pods, err = sidecarTester.GetSelectorPods(deployment.Namespace, deployment.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if !pod.DeletionTimestamp.IsZero() || pod.Spec.Containers[0].Image != "busybox:1.33" {
|
||||
continue
|
||||
}
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(2))
|
||||
ginkgo.By("PodUnavailableBudget targetReference pods, update failed image and block done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector two deployments, deployment.strategy.maxUnavailable=100%, pub.spec.maxUnavailable=20%, and update success image", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
pub.Spec.MaxUnavailable = &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "20%",
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create deployment1
|
||||
deployment := tester.NewBaseDeployment(ns)
|
||||
deployment.Spec.Replicas = utilpointer.Int32Ptr(5)
|
||||
deploymentIn1 := deployment.DeepCopy()
|
||||
deploymentIn1.Name = fmt.Sprintf("%s-1", deploymentIn1.Name)
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment1(%s.%s)", deploymentIn1.Namespace, deploymentIn1.Name))
|
||||
tester.CreateDeployment(deploymentIn1)
|
||||
// create deployment2
|
||||
deploymentIn2 := deployment.DeepCopy()
|
||||
deploymentIn2.Name = fmt.Sprintf("%s-2", deploymentIn1.Name)
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment2(%s.%s)", deploymentIn2.Namespace, deploymentIn2.Name))
|
||||
tester.CreateDeployment(deploymentIn2)
|
||||
|
||||
// wait 1 seconds
|
||||
ginkgo.By(fmt.Sprintf("wait 1 seconds, check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second)
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update Deployment-1 and deployment-2 with success image(busybox:1.33)"))
|
||||
deploymentIn1.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
_, err = c.AppsV1().Deployments(deploymentIn1.Namespace).Update(context.TODO(), deploymentIn1, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
deploymentIn2.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
_, err = c.AppsV1().Deployments(deploymentIn2.Namespace).Update(context.TODO(), deploymentIn2, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
// wait 1 seconds, and check deployment, pub Status
|
||||
ginkgo.By(fmt.Sprintf("wait 1 seconds, and check deployment, pub Status"))
|
||||
time.Sleep(time.Second)
|
||||
// check deployment
|
||||
tester.WaitForDeploymentMinReadyAndRunning([]*apps.Deployment{deploymentIn1, deploymentIn2}, 8)
|
||||
// check pods
|
||||
pods, err := sidecarTester.GetSelectorPods(deployment.Namespace, deployment.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if !pod.DeletionTimestamp.IsZero() || pod.Spec.Containers[0].Image != "busybox:1.33" {
|
||||
continue
|
||||
}
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(10))
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
ginkgo.By("PodUnavailableBudget selector two deployments, deployment.strategy.maxUnavailable=100%, pub.spec.maxUnavailable=20%, and update success image done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector SidecarSet, inject sidecar container, update failed sidecar image, block", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create sidecarset
|
||||
sidecarSet := sidecarTester.NewBaseSidecarSet(ns)
|
||||
sidecarSet.Spec.Namespace = ns
|
||||
sidecarSet.Spec.Selector = &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "busybox",
|
||||
},
|
||||
}
|
||||
sidecarSet.Spec.Containers = []appsv1alpha1.SidecarContainer{
|
||||
{
|
||||
Container: corev1.Container{
|
||||
Name: "nginx-sidecar",
|
||||
Image: "nginx:1.18",
|
||||
Command: []string{"tail", "-f", "/dev/null"},
|
||||
},
|
||||
},
|
||||
}
|
||||
sidecarSet.Spec.UpdateStrategy = appsv1alpha1.SidecarSetUpdateStrategy{
|
||||
Type: appsv1alpha1.RollingUpdateSidecarSetStrategyType,
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "100%",
|
||||
},
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating SidecarSet %s", sidecarSet.Name))
|
||||
sidecarSet = sidecarTester.CreateSidecarSet(sidecarSet)
|
||||
|
||||
// create deployment
|
||||
deployment := tester.NewBaseDeployment(ns)
|
||||
deployment.Spec.Replicas = utilpointer.Int32Ptr(5)
|
||||
ginkgo.By(fmt.Sprintf("Creating Deployment(%s.%s)", deployment.Namespace, deployment.Name))
|
||||
tester.CreateDeployment(deployment)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
// check sidecarSet inject sidecar container
|
||||
ginkgo.By(fmt.Sprintf("check sidecarSet inject sidecar container and pub status"))
|
||||
pods, err := sidecarTester.GetSelectorPods(deployment.Namespace, deployment.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
pod := pods[0]
|
||||
gomega.Expect(pod.Spec.Containers).To(gomega.HaveLen(len(deployment.Spec.Template.Spec.Containers) + len(sidecarSet.Spec.Containers)))
|
||||
|
||||
//check pub status
|
||||
time.Sleep(time.Second)
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 4,
|
||||
CurrentAvailable: 5,
|
||||
TotalReplicas: 5,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update sidecar container failed image
|
||||
ginkgo.By(fmt.Sprintf("update sidecar container failed image(nginx:failed)"))
|
||||
sidecarSet, err = kc.AppsV1alpha1().SidecarSets().Get(context.TODO(), sidecarSet.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
sidecarSet.Spec.Containers[0].Image = "nginx:failed"
|
||||
sidecarTester.UpdateSidecarSet(sidecarSet)
|
||||
|
||||
// wait 1 seconds, and check sidecarSet upgrade block
|
||||
ginkgo.By(fmt.Sprintf("wait 1 seconds, and check sidecarSet upgrade block"))
|
||||
time.Sleep(time.Second)
|
||||
except := &appsv1alpha1.SidecarSetStatus{
|
||||
MatchedPods: 5,
|
||||
UpdatedPods: 1,
|
||||
UpdatedReadyPods: 0,
|
||||
ReadyPods: 4,
|
||||
}
|
||||
sidecarTester.WaitForSidecarSetMinReadyAndUpgrade(sidecarSet, except, 4)
|
||||
time.Sleep(time.Second)
|
||||
//check pub status
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 4,
|
||||
CurrentAvailable: 4,
|
||||
TotalReplicas: 5,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
// check unavailablePods
|
||||
gomega.Expect(nowStatus.UnavailablePods).To(gomega.HaveLen(1))
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update sidecar container success image
|
||||
ginkgo.By(fmt.Sprintf("update sidecar container success image"))
|
||||
sidecarSet, err = kc.AppsV1alpha1().SidecarSets().Get(context.TODO(), sidecarSet.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
sidecarSet.Spec.Containers[0].Image = "nginx:1.19"
|
||||
sidecarTester.UpdateSidecarSet(sidecarSet)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
// check sidecarSet upgrade success
|
||||
ginkgo.By(fmt.Sprintf("check sidecarSet upgrade success"))
|
||||
except = &appsv1alpha1.SidecarSetStatus{
|
||||
MatchedPods: 5,
|
||||
UpdatedPods: 5,
|
||||
UpdatedReadyPods: 5,
|
||||
ReadyPods: 5,
|
||||
}
|
||||
sidecarTester.WaitForSidecarSetMinReadyAndUpgrade(sidecarSet, except, 4)
|
||||
time.Sleep(time.Second)
|
||||
//check pub status
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 4,
|
||||
CurrentAvailable: 5,
|
||||
TotalReplicas: 5,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
ginkgo.By("PodUnavailableBudget selector pods, inject sidecar container, update failed sidecar image, block done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector cloneSet, strategy.type=recreate, update failed image and block", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create cloneset
|
||||
cloneset := tester.NewBaseCloneSet(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating CloneSet(%s.%s)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset = tester.CreateCloneSet(cloneset)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update failed image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) with failed image(busybox:failed)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset.Spec.Template.Spec.Containers[0].Image = "busybox:failed"
|
||||
_, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), cloneset, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("waiting 20 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second * 20)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 1,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// check now pod
|
||||
pods, err := sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
noUpdatePods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.Spec.Containers[0].Image == "busybox:failed" || !pod.DeletionTimestamp.IsZero() {
|
||||
continue
|
||||
}
|
||||
noUpdatePods = append(noUpdatePods, *pod)
|
||||
}
|
||||
gomega.Expect(noUpdatePods).To(gomega.HaveLen(1))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) success image(busybox:1.33)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset, _ = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
cloneset.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
cloneset, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), cloneset, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
tester.WaitForCloneSetMinReadyAndRunning([]*appsv1alpha1.CloneSet{cloneset}, 1)
|
||||
|
||||
// check pub status
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
//check pods
|
||||
pods, err = sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if !pod.DeletionTimestamp.IsZero() || pod.Spec.Containers[0].Image != "busybox:1.33" {
|
||||
continue
|
||||
}
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(2))
|
||||
ginkgo.By("PodUnavailableBudget selector cloneSet, update failed image and block done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector cloneSet, strategy.type=in-place, update failed image and block", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create cloneset
|
||||
cloneset := tester.NewBaseCloneSet(ns)
|
||||
cloneset.Spec.UpdateStrategy.Type = appsv1alpha1.InPlaceOnlyCloneSetUpdateStrategyType
|
||||
ginkgo.By(fmt.Sprintf("Creating CloneSet(%s.%s)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset = tester.CreateCloneSet(cloneset)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update failed image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) with failed image(busybox:failed)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset.Spec.Template.Spec.Containers[0].Image = "busybox:failed"
|
||||
_, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), cloneset, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("waiting 20 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second * 20)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 1,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// check now pod
|
||||
pods, err := sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
noUpdatePods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.Spec.Containers[0].Image == "busybox:failed" || !pod.DeletionTimestamp.IsZero() {
|
||||
continue
|
||||
}
|
||||
noUpdatePods = append(noUpdatePods, *pod)
|
||||
}
|
||||
gomega.Expect(noUpdatePods).To(gomega.HaveLen(1))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) success image(busybox:1.33)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset, _ = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
cloneset.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
cloneset, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), cloneset, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
tester.WaitForCloneSetMinReadyAndRunning([]*appsv1alpha1.CloneSet{cloneset}, 1)
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 1,
|
||||
DesiredAvailable: 1,
|
||||
CurrentAvailable: 2,
|
||||
TotalReplicas: 2,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
//check pods
|
||||
pods, err = sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if !pod.DeletionTimestamp.IsZero() || pod.Spec.Containers[0].Image != "busybox:1.33" {
|
||||
continue
|
||||
}
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(2))
|
||||
ginkgo.By("PodUnavailableBudget selector cloneSet, update failed image and block done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector two cloneSets, strategy.type=in-place, update success image", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
pub.Spec.MaxUnavailable = &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "20%",
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create cloneset1
|
||||
cloneset := tester.NewBaseCloneSet(ns)
|
||||
cloneset.Spec.Replicas = utilpointer.Int32Ptr(5)
|
||||
cloneset.Spec.UpdateStrategy.Type = appsv1alpha1.InPlaceIfPossibleCloneSetUpdateStrategyType
|
||||
clonesetIn1 := cloneset.DeepCopy()
|
||||
clonesetIn1.Name = fmt.Sprintf("%s-1", clonesetIn1.Name)
|
||||
ginkgo.By(fmt.Sprintf("Creating CloneSet1(%s.%s)", clonesetIn1.Namespace, clonesetIn1.Name))
|
||||
clonesetIn1 = tester.CreateCloneSet(clonesetIn1)
|
||||
//create cloneSet2
|
||||
clonesetIn2 := cloneset.DeepCopy()
|
||||
clonesetIn2.Name = fmt.Sprintf("%s-2", clonesetIn2.Name)
|
||||
ginkgo.By(fmt.Sprintf("Creating CloneSet2(%s.%s)", clonesetIn2.Namespace, clonesetIn2.Name))
|
||||
clonesetIn2 = tester.CreateCloneSet(clonesetIn2)
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 10)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err := kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update failed image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) with failed image(busybox:failed)", cloneset.Namespace, cloneset.Name))
|
||||
clonesetIn1.Spec.Template.Spec.Containers[0].Image = "busybox:failed"
|
||||
_, err = kc.AppsV1alpha1().CloneSets(clonesetIn1.Namespace).Update(context.TODO(), clonesetIn1, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
clonesetIn2.Spec.Template.Spec.Containers[0].Image = "busybox:failed"
|
||||
_, err = kc.AppsV1alpha1().CloneSets(clonesetIn2.Namespace).Update(context.TODO(), clonesetIn2, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("waiting 20 seconds, and check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
time.Sleep(time.Second * 20)
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 0,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 8,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// check now pod
|
||||
pods, err := sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
noUpdatePods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.Spec.Containers[0].Image == "busybox:failed" || !pod.DeletionTimestamp.IsZero() {
|
||||
continue
|
||||
}
|
||||
noUpdatePods = append(noUpdatePods, *pod)
|
||||
}
|
||||
gomega.Expect(noUpdatePods).To(gomega.HaveLen(8))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) success image(busybox:1.33)", cloneset.Namespace, cloneset.Name))
|
||||
clonesetIn1, _ = kc.AppsV1alpha1().CloneSets(clonesetIn1.Namespace).Get(context.TODO(), clonesetIn1.Name, metav1.GetOptions{})
|
||||
clonesetIn1.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
clonesetIn1, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), clonesetIn1, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
// update success image
|
||||
clonesetIn2, _ = kc.AppsV1alpha1().CloneSets(clonesetIn2.Namespace).Get(context.TODO(), clonesetIn2.Name, metav1.GetOptions{})
|
||||
clonesetIn2.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
clonesetIn2, err = kc.AppsV1alpha1().CloneSets(clonesetIn2.Namespace).Update(context.TODO(), clonesetIn2, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
tester.WaitForCloneSetMinReadyAndRunning([]*appsv1alpha1.CloneSet{clonesetIn1, clonesetIn2}, 7)
|
||||
|
||||
// check pub status
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
//check pods
|
||||
pods, err = sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.DeletionTimestamp.IsZero() && pod.Spec.Containers[0].Image == "busybox:1.33" {
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(10))
|
||||
ginkgo.By("PodUnavailableBudget selector two cloneSets, strategy.type=in-place, update success image done")
|
||||
})
|
||||
|
||||
ginkgo.It("PodUnavailableBudget selector cloneSet and sidecarSet, strategy.type=in-place, update success image", func() {
|
||||
// create pub
|
||||
pub := tester.NewBasePub(ns)
|
||||
pub.Spec.MaxUnavailable = &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "20%",
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating PodUnavailableBudget(%s.%s)", pub.Namespace, pub.Name))
|
||||
tester.CreatePub(pub)
|
||||
|
||||
// create sidecarSet
|
||||
sidecarSet := sidecarTester.NewBaseSidecarSet(ns)
|
||||
sidecarSet.Spec.Namespace = ns
|
||||
sidecarSet.Spec.Selector = &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"app": "busybox",
|
||||
},
|
||||
}
|
||||
sidecarSet.Spec.Containers = []appsv1alpha1.SidecarContainer{
|
||||
{
|
||||
Container: corev1.Container{
|
||||
Name: "nginx-sidecar",
|
||||
Image: "nginx:1.18",
|
||||
Command: []string{"tail", "-f", "/dev/null"},
|
||||
},
|
||||
},
|
||||
}
|
||||
sidecarSet.Spec.UpdateStrategy = appsv1alpha1.SidecarSetUpdateStrategy{
|
||||
Type: appsv1alpha1.RollingUpdateSidecarSetStrategyType,
|
||||
MaxUnavailable: &intstr.IntOrString{
|
||||
Type: intstr.String,
|
||||
StrVal: "100%",
|
||||
},
|
||||
}
|
||||
ginkgo.By(fmt.Sprintf("Creating SidecarSet %s", sidecarSet.Name))
|
||||
sidecarSet = sidecarTester.CreateSidecarSet(sidecarSet)
|
||||
|
||||
// create cloneset
|
||||
cloneset := tester.NewBaseCloneSet(ns)
|
||||
cloneset.Spec.UpdateStrategy.Type = appsv1alpha1.InPlaceOnlyCloneSetUpdateStrategyType
|
||||
cloneset.Spec.Replicas = utilpointer.Int32Ptr(10)
|
||||
ginkgo.By(fmt.Sprintf("Creating CloneSet(%s.%s)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset = tester.CreateCloneSet(cloneset)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
// check sidecarSet inject sidecar container
|
||||
ginkgo.By(fmt.Sprintf("check sidecarSet inject sidecar container and pub status"))
|
||||
pods, err := sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
pod := pods[0]
|
||||
gomega.Expect(pod.Spec.Containers).To(gomega.HaveLen(len(cloneset.Spec.Template.Spec.Containers) + len(sidecarSet.Spec.Containers)))
|
||||
|
||||
// wait 10 seconds
|
||||
time.Sleep(time.Second * 5)
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus := &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus := &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
// update success image
|
||||
ginkgo.By(fmt.Sprintf("update CloneSet(%s.%s) success image(busybox:1.33)", cloneset.Namespace, cloneset.Name))
|
||||
cloneset, _ = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Get(context.TODO(), cloneset.Name, metav1.GetOptions{})
|
||||
cloneset.Spec.Template.Spec.Containers[0].Image = "busybox:1.33"
|
||||
cloneset, err = kc.AppsV1alpha1().CloneSets(cloneset.Namespace).Update(context.TODO(), cloneset, metav1.UpdateOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
// update sidecar container success image
|
||||
ginkgo.By(fmt.Sprintf("update sidecar container success image"))
|
||||
sidecarSet.Spec.Containers[0].Image = "nginx:1.19"
|
||||
sidecarTester.UpdateSidecarSet(sidecarSet)
|
||||
time.Sleep(time.Second)
|
||||
tester.WaitForCloneSetMinReadyAndRunning([]*appsv1alpha1.CloneSet{cloneset}, 2)
|
||||
|
||||
//wait 20 seconds
|
||||
ginkgo.By(fmt.Sprintf("check PodUnavailableBudget(%s.%s) Status", pub.Namespace, pub.Name))
|
||||
expectStatus = &policyv1alpha1.PodUnavailableBudgetStatus{
|
||||
UnavailableAllowed: 2,
|
||||
DesiredAvailable: 8,
|
||||
CurrentAvailable: 10,
|
||||
TotalReplicas: 10,
|
||||
}
|
||||
setPubStatus(expectStatus)
|
||||
pub, err = kc.PolicyV1alpha1().PodUnavailableBudgets(pub.Namespace).Get(context.TODO(), pub.Name, metav1.GetOptions{})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
nowStatus = &pub.Status
|
||||
setPubStatus(nowStatus)
|
||||
gomega.Expect(nowStatus).To(gomega.Equal(expectStatus))
|
||||
|
||||
//check pods
|
||||
pods, err = sidecarTester.GetSelectorPods(cloneset.Namespace, cloneset.Spec.Selector)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
newPods := make([]corev1.Pod, 0)
|
||||
for _, pod := range pods {
|
||||
if pod.DeletionTimestamp.IsZero() && pod.Spec.Containers[1].Image == "busybox:1.33" && pod.Spec.Containers[0].Image == "nginx:1.19" {
|
||||
newPods = append(newPods, *pod)
|
||||
}
|
||||
}
|
||||
gomega.Expect(newPods).To(gomega.HaveLen(10))
|
||||
ginkgo.By("PodUnavailableBudget selector cloneSet, update failed image and block done")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func setPubStatus(status *policyv1alpha1.PodUnavailableBudgetStatus) {
|
||||
status.DisruptedPods = nil
|
||||
status.UnavailablePods = nil
|
||||
status.ObservedGeneration = 0
|
||||
}
|
||||
Loading…
Reference in New Issue