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 minimum desired number of available pods
|
||||||
DesiredAvailable int32 `json:"desiredAvailable"`
|
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"`
|
TotalReplicas int32 `json:"totalReplicas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ spec:
|
||||||
format: int64
|
format: int64
|
||||||
type: integer
|
type: integer
|
||||||
totalReplicas:
|
totalReplicas:
|
||||||
description: TotalReplicas total number of pods counted by this budget
|
description: TotalReplicas total number of pods counted by this unavailable budget
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
unavailableAllowed:
|
unavailableAllowed:
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ package pubcontrol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||||
|
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PubControl interface {
|
type PubControl interface {
|
||||||
|
|
@ -32,12 +33,17 @@ type PubControl interface {
|
||||||
IsPodReady(pod *corev1.Pod) bool
|
IsPodReady(pod *corev1.Pod) bool
|
||||||
// IsPodStateConsistent indicates whether pod.spec and pod.status are consistent after updating containers
|
// IsPodStateConsistent indicates whether pod.spec and pod.status are consistent after updating containers
|
||||||
IsPodStateConsistent(pod *corev1.Pod) bool
|
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
|
// webhook
|
||||||
// determine if this change to pod might cause unavailability
|
// determine if this change to pod might cause unavailability
|
||||||
IsPodUnavailableChanged(oldPod, newPod *corev1.Pod) bool
|
IsPodUnavailableChanged(oldPod, newPod *corev1.Pod) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPubControl(pub *policyv1alpha1.PodUnavailableBudget) PubControl {
|
func NewPubControl(pub *policyv1alpha1.PodUnavailableBudget, controllerFinder *controllerfinder.ControllerFinder, client client.Client) PubControl {
|
||||||
return &commonControl{PodUnavailableBudget: pub}
|
return &commonControl{PodUnavailableBudget: pub, controllerFinder: controllerFinder, Client: client}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,26 @@ limitations under the License.
|
||||||
package pubcontrol
|
package pubcontrol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||||
"github.com/openkruise/kruise/pkg/control/sidecarcontrol"
|
"github.com/openkruise/kruise/pkg/control/sidecarcontrol"
|
||||||
"github.com/openkruise/kruise/pkg/util"
|
"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/inplaceupdate"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
kubecontroller "k8s.io/kubernetes/pkg/controller"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
type commonControl struct {
|
type commonControl struct {
|
||||||
|
client.Client
|
||||||
*policyv1alpha1.PodUnavailableBudget
|
*policyv1alpha1.PodUnavailableBudget
|
||||||
|
controllerFinder *controllerfinder.ControllerFinder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commonControl) GetPodUnavailableBudget() *policyv1alpha1.PodUnavailableBudget {
|
func (c *commonControl) GetPodUnavailableBudget() *policyv1alpha1.PodUnavailableBudget {
|
||||||
|
|
@ -58,6 +63,49 @@ func (c *commonControl) IsPodUnavailableChanged(oldPod, newPod *corev1.Pod) bool
|
||||||
return false
|
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 {
|
func (c *commonControl) IsPodStateConsistent(pod *corev1.Pod) bool {
|
||||||
// if all container image is digest format
|
// if all container image is digest format
|
||||||
// by comparing status.containers[x].ImageID with spec.container[x].Image can determine whether pod is consistent
|
// 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"
|
appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
|
||||||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
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/inplaceupdate"
|
||||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||||
apps "k8s.io/api/apps/v1"
|
apps "k8s.io/api/apps/v1"
|
||||||
|
|
@ -48,6 +49,7 @@ type realControl struct {
|
||||||
lifecycleControl lifecycle.Interface
|
lifecycleControl lifecycle.Interface
|
||||||
inplaceControl inplaceupdate.Interface
|
inplaceControl inplaceupdate.Interface
|
||||||
recorder record.EventRecorder
|
recorder record.EventRecorder
|
||||||
|
controllerFinder *controllerfinder.ControllerFinder
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(c client.Client, recorder record.EventRecorder) Interface {
|
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),
|
inplaceControl: inplaceupdate.New(c, clonesetutils.RevisionAdapterImpl),
|
||||||
lifecycleControl: lifecycle.New(c),
|
lifecycleControl: lifecycle.New(c),
|
||||||
recorder: recorder,
|
recorder: recorder,
|
||||||
|
controllerFinder: controllerfinder.NewControllerFinder(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
||||||
"github.com/openkruise/kruise/pkg/features"
|
"github.com/openkruise/kruise/pkg/features"
|
||||||
"github.com/openkruise/kruise/pkg/util"
|
"github.com/openkruise/kruise/pkg/util"
|
||||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
|
||||||
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
|
utilfeature "github.com/openkruise/kruise/pkg/util/feature"
|
||||||
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
"github.com/openkruise/kruise/pkg/util/inplaceupdate"
|
||||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||||
|
|
@ -122,7 +121,7 @@ func (c *realControl) Update(cs *appsv1alpha1.CloneSet,
|
||||||
var pub *policyv1alpha1.PodUnavailableBudget
|
var pub *policyv1alpha1.PodUnavailableBudget
|
||||||
var err error
|
var err error
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.PodUnavailableBudgetUpdateGate) && len(waitUpdateIndexes) > 0 {
|
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 {
|
if err != nil {
|
||||||
return requeueDuration.Get(), err
|
return requeueDuration.Get(), err
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +131,7 @@ func (c *realControl) Update(cs *appsv1alpha1.CloneSet,
|
||||||
pod := pods[idx]
|
pod := pods[idx]
|
||||||
// Determine the pub before updating the pod
|
// Determine the pub before updating the pod
|
||||||
if pub != nil {
|
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 {
|
if err != nil {
|
||||||
return requeueDuration.Get(), err
|
return requeueDuration.Get(), err
|
||||||
// pub check does not pass, try again in seconds
|
// pub check does not pass, try again in seconds
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
clonesetcore "github.com/openkruise/kruise/pkg/controller/cloneset/core"
|
clonesetcore "github.com/openkruise/kruise/pkg/controller/cloneset/core"
|
||||||
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
clonesetutils "github.com/openkruise/kruise/pkg/controller/cloneset/utils"
|
||||||
"github.com/openkruise/kruise/pkg/util"
|
"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/inplaceupdate"
|
||||||
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
"github.com/openkruise/kruise/pkg/util/lifecycle"
|
||||||
apps "k8s.io/api/apps/v1"
|
apps "k8s.io/api/apps/v1"
|
||||||
|
|
@ -573,6 +574,7 @@ func TestUpdate(t *testing.T) {
|
||||||
lifecycle.NewForTest(fakeClient),
|
lifecycle.NewForTest(fakeClient),
|
||||||
inplaceupdate.NewForTest(fakeClient, clonesetutils.RevisionAdapterImpl, func() metav1.Time { return now }),
|
inplaceupdate.NewForTest(fakeClient, clonesetutils.RevisionAdapterImpl, func() metav1.Time { return now }),
|
||||||
record.NewFakeRecorder(10),
|
record.NewFakeRecorder(10),
|
||||||
|
controllerfinder.NewControllerFinder(fakeClient),
|
||||||
}
|
}
|
||||||
currentRevision := mc.updateRevision
|
currentRevision := mc.updateRevision
|
||||||
if len(mc.revisions) > 0 {
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -189,8 +190,8 @@ func (r *ReconcilePodUnavailableBudget) syncPodUnavailableBudget(pub *policyv1al
|
||||||
r.recorder.Eventf(pub, corev1.EventTypeNormal, "NoPods", "No matching pods found")
|
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))
|
klog.V(3).Infof("pub(%s.%s) controller pods(%d) expectedCount(%d)", pub.Namespace, pub.Name, len(pods), expectedCount)
|
||||||
expectedCount, desiredAvailable, err := r.getExpectedPodCount(pub, pods)
|
desiredAvailable, err := r.getDesiredAvailableForPub(pub, expectedCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.recorder.Eventf(pub, corev1.EventTypeWarning, "CalculateExpectedPodCountFailed", "Failed to calculate the number of expected pods: %v", err)
|
r.recorder.Eventf(pub, corev1.EventTypeWarning, "CalculateExpectedPodCountFailed", "Failed to calculate the number of expected pods: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -200,7 +201,6 @@ func (r *ReconcilePodUnavailableBudget) syncPodUnavailableBudget(pub *policyv1al
|
||||||
var conflictTimes int
|
var conflictTimes int
|
||||||
var costOfGet, costOfUpdate time.Duration
|
var costOfGet, costOfUpdate time.Duration
|
||||||
|
|
||||||
control := pubcontrol.NewPubControl(pub)
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
var pubClone *policyv1alpha1.PodUnavailableBudget
|
var pubClone *policyv1alpha1.PodUnavailableBudget
|
||||||
refresh := false
|
refresh := false
|
||||||
|
|
@ -328,14 +328,10 @@ func (r *ReconcilePodUnavailableBudget) getPodsForPub(pub *policyv1alpha1.PodUna
|
||||||
return matchedPods, nil
|
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 {
|
if pub.Spec.MaxUnavailable != nil {
|
||||||
expectedCount, err = r.getExpectedScale(pub, pods)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var maxUnavailable int
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -347,15 +343,9 @@ func (r *ReconcilePodUnavailableBudget) getExpectedPodCount(pub *policyv1alpha1.
|
||||||
} else if pub.Spec.MinAvailable != nil {
|
} else if pub.Spec.MinAvailable != nil {
|
||||||
if pub.Spec.MinAvailable.Type == intstr.Int {
|
if pub.Spec.MinAvailable.Type == intstr.Int {
|
||||||
desiredAvailable = pub.Spec.MinAvailable.IntVal
|
desiredAvailable = pub.Spec.MinAvailable.IntVal
|
||||||
expectedCount = int32(len(pods))
|
|
||||||
} else if pub.Spec.MinAvailable.Type == intstr.String {
|
} else if pub.Spec.MinAvailable.Type == intstr.String {
|
||||||
expectedCount, err = r.getExpectedScale(pub, pods)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var minAvailable int
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -457,7 +447,7 @@ func (r *ReconcilePodUnavailableBudget) buildDisruptedAndUnavailablePods(pods []
|
||||||
// handle unavailable pods which have been in-updated specification
|
// handle unavailable pods which have been in-updated specification
|
||||||
unavailableTime, found := unavailablePods[pod.Name]
|
unavailableTime, found := unavailablePods[pod.Name]
|
||||||
if found {
|
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)
|
expectedUpdate := unavailableTime.Time.Add(UpdatedDelayCheckTime)
|
||||||
if expectedUpdate.Before(currentTime) {
|
if expectedUpdate.Before(currentTime) {
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
policyv1alpha1 "github.com/openkruise/kruise/apis/policy/v1alpha1"
|
||||||
"github.com/openkruise/kruise/pkg/util"
|
"github.com/openkruise/kruise/pkg/util"
|
||||||
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
"github.com/openkruise/kruise/pkg/util/controllerfinder"
|
||||||
|
|
||||||
apps "k8s.io/api/apps/v1"
|
apps "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
@ -425,7 +424,7 @@ func TestPubReconcile(t *testing.T) {
|
||||||
UnavailableAllowed: 0,
|
UnavailableAllowed: 0,
|
||||||
CurrentAvailable: 5,
|
CurrentAvailable: 5,
|
||||||
DesiredAvailable: 100,
|
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)
|
oldPub, _ := pubcontrol.GetPodUnavailableBudgetForPod(p.client, p.controllerFinder, oldPod)
|
||||||
newPub, _ := pubcontrol.GetPodUnavailableBudgetForPod(p.client, p.controllerFinder, newPod)
|
newPub, _ := pubcontrol.GetPodUnavailableBudgetForPod(p.client, p.controllerFinder, newPod)
|
||||||
if oldPub != nil && newPub != nil && oldPub.Name == newPub.Name {
|
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 {
|
if isReconcile, enqueueDelayTime := isPodAvailableChanged(oldPod, newPod, newPub, control); isReconcile {
|
||||||
q.AddAfter(reconcile.Request{
|
q.AddAfter(reconcile.Request{
|
||||||
NamespacedName: types.NamespacedName{
|
NamespacedName: types.NamespacedName{
|
||||||
|
|
@ -124,7 +124,7 @@ func (p *enqueueRequestForPod) updatePod(q workqueue.RateLimitingInterface, old,
|
||||||
if pub == nil {
|
if pub == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
control := pubcontrol.NewPubControl(pub)
|
control := pubcontrol.NewPubControl(pub, p.controllerFinder, p.client)
|
||||||
if isReconcile, enqueueDelayTime := isPodAvailableChanged(oldPod, newPod, pub, control); isReconcile {
|
if isReconcile, enqueueDelayTime := isPodAvailableChanged(oldPod, newPod, pub, control); isReconcile {
|
||||||
q.AddAfter(reconcile.Request{
|
q.AddAfter(reconcile.Request{
|
||||||
NamespacedName: types.NamespacedName{
|
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) {
|
func (r *ControllerFinder) GetScaleAndSelectorForRef(apiVersion, kind, ns, name string, uid types.UID) (*ScaleAndSelector, error) {
|
||||||
targetRef := ControllerReference{
|
targetRef := ControllerReference{
|
||||||
APIVersion: apiVersion,
|
APIVersion: apiVersion,
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ func (p *PodCreateHandler) podUnavailableBudgetValidatingPod(ctx context.Context
|
||||||
if pub == nil {
|
if pub == nil {
|
||||||
return true, "", 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)
|
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
|
// the change will not cause pod unavailability, then pass
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
// volume
|
// volume
|
||||||
for _, volume := range cs.exceptVolumes {
|
for _, volume := range cs.exceptVolumes {
|
||||||
object := util.GetPodVolume(&pods[0], volume)
|
object := util.GetPodVolume(pods[0], volume)
|
||||||
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
||||||
}
|
}
|
||||||
// volumeMounts
|
// volumeMounts
|
||||||
|
|
@ -318,7 +318,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
// volume
|
// volume
|
||||||
for _, volume := range cs.exceptVolumes {
|
for _, volume := range cs.exceptVolumes {
|
||||||
object := util.GetPodVolume(&pods[0], volume)
|
object := util.GetPodVolume(pods[0], volume)
|
||||||
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
gomega.Expect(object).ShouldNot(gomega.BeNil())
|
||||||
}
|
}
|
||||||
// volumeMounts
|
// volumeMounts
|
||||||
|
|
@ -486,13 +486,13 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
origin.Insert(sidecar.Name)
|
origin.Insert(sidecar.Name)
|
||||||
}
|
}
|
||||||
// SidecarSetHashAnnotation = "kruise.io/sidecarset-hash"
|
// 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.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||||
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
||||||
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
||||||
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
||||||
// SidecarSetHashWithoutImageAnnotation = "kruise.io/sidecarset-hash-without-image"
|
// 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.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||||
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
||||||
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
||||||
|
|
@ -534,13 +534,13 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
origin.Insert(sidecar.Name)
|
origin.Insert(sidecar.Name)
|
||||||
}
|
}
|
||||||
// SidecarSetHashAnnotation = "kruise.io/sidecarset-hash"
|
// 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.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||||
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
gomega.Expect(upgradeSpec1.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetRevision(sidecarSetIn)))
|
||||||
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
target1 := sets.NewString(upgradeSpec1.SidecarList...)
|
||||||
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
gomega.Expect(reflect.DeepEqual(origin.List(), target1.List())).To(gomega.Equal(true))
|
||||||
// SidecarSetHashWithoutImageAnnotation = "kruise.io/sidecarset-hash-without-image"
|
// 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.SidecarSetName).To(gomega.Equal(sidecarSetIn.Name))
|
||||||
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
gomega.Expect(upgradeSpec2.SidecarSetHash).To(gomega.Equal(sidecarcontrol.GetSidecarSetWithoutImageRevision(sidecarSetIn)))
|
||||||
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
target2 := sets.NewString(upgradeSpec2.SidecarList...)
|
||||||
|
|
@ -614,7 +614,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||||
canaryPod := pods[0]
|
canaryPod := pods[0]
|
||||||
canaryPod.Labels["canary.release"] = "true"
|
canaryPod.Labels["canary.release"] = "true"
|
||||||
tester.UpdatePod(&canaryPod)
|
tester.UpdatePod(canaryPod)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
// update sidecarSet sidecar container
|
// update sidecarSet sidecar container
|
||||||
sidecarSetIn.Spec.Containers[0].Image = "busybox:latest"
|
sidecarSetIn.Spec.Containers[0].Image = "busybox:latest"
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ var _ = SIGDescribe("SidecarSet", func() {
|
||||||
"nginx-sidecar-2": "busybox:latest",
|
"nginx-sidecar-2": "busybox:latest",
|
||||||
}
|
}
|
||||||
for sidecar, image := range exceptContainer {
|
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).ShouldNot(gomega.BeNil())
|
||||||
gomega.Expect(sidecarContainer.Image).To(gomega.Equal(image))
|
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)
|
pods, err := tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
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)
|
workSidecarContainer := util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
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)
|
pods, err = tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
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)
|
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
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)
|
pods, err = tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
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)
|
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
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)
|
pods, err := tester.GetSelectorPods(deploymentIn.Namespace, deploymentIn.Spec.Selector)
|
||||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
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)
|
workSidecarContainer := util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn)["nginx-sidecar"], podIn)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.18"))
|
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(err).NotTo(gomega.HaveOccurred())
|
||||||
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
gomega.Expect(pods).To(gomega.HaveLen(int(*deploymentIn.Spec.Replicas)))
|
||||||
// pod[0]
|
// pod[0]
|
||||||
podIn1 := &pods[0]
|
podIn1 := pods[0]
|
||||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn1)["nginx-sidecar"], podIn1)
|
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn1)["nginx-sidecar"], podIn1)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
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.Name).To(gomega.Equal("nginx-sidecar-1"))
|
||||||
gomega.Expect(emptySidecarContainer.Image).To(gomega.Equal("busybox:latest"))
|
gomega.Expect(emptySidecarContainer.Image).To(gomega.Equal("busybox:latest"))
|
||||||
// pod[1]
|
// pod[1]
|
||||||
podIn2 := &pods[1]
|
podIn2 := pods[1]
|
||||||
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn2)["nginx-sidecar"], podIn2)
|
workSidecarContainer = util.GetContainer(sidecarcontrol.GetPodHotUpgradeInfoInAnnotations(podIn2)["nginx-sidecar"], podIn2)
|
||||||
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
gomega.Expect(workSidecarContainer.Name).To(gomega.Equal("nginx-sidecar-2"))
|
||||||
gomega.Expect(workSidecarContainer.Image).To(gomega.Equal("nginx:1.19"))
|
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)
|
faster, err := util.GetFastLabelSelector(selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -319,7 +319,14 @@ func (s *SidecarSetTester) GetSelectorPods(namespace string, selector *metav1.La
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
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