mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-10 12:32:03 +00:00
integration tests for pod resize
This commit is contained in:
parent
33a3d7578b
commit
f1093962b6
@ -23,6 +23,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -678,6 +679,253 @@ func TestPodUpdateEphemeralContainers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPodResize(t *testing.T) {
|
||||||
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
|
server := kubeapiservertesting.StartTestServerOrDie(t, nil,
|
||||||
|
append(framework.DefaultTestServerFlags(), "--feature-gates=InPlacePodVerticalScaling=true"),
|
||||||
|
framework.SharedEtcd())
|
||||||
|
defer server.TearDownFn()
|
||||||
|
|
||||||
|
client := clientset.NewForConfigOrDie(server.ClientConfig)
|
||||||
|
|
||||||
|
ns := framework.CreateNamespaceOrDie(client, "pod-create-ephemeral-containers", t)
|
||||||
|
defer framework.DeleteNamespaceOrDie(client, ns, t)
|
||||||
|
|
||||||
|
testPod := func(name string) *v1.Pod {
|
||||||
|
return &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "fake-name",
|
||||||
|
Image: "fakeimage",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCases := []struct {
|
||||||
|
name string
|
||||||
|
originalRes v1.ResourceRequirements
|
||||||
|
resize v1.ResourceRequirements
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "cpu request change",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("10m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resize: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("20m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "memory request change",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resize: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceMemory: resource.MustParse("2Gi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "storage request change",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceEphemeralStorage: resource.MustParse("1Gi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resize: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceEphemeralStorage: resource.MustParse("2Gi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range resizeCases {
|
||||||
|
pod := testPod("resize")
|
||||||
|
pod.Spec.Containers[0].Resources = tc.originalRes
|
||||||
|
resp, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error when creating pod: %v", err)
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part 1. Resize
|
||||||
|
resp.Spec.Containers[0].Resources = tc.resize
|
||||||
|
if _, err := client.CoreV1().Pods(ns.Name).Update(context.TODO(), resp, metav1.UpdateOptions{}); err == nil {
|
||||||
|
t.Fatalf("Unexpected allowed pod update")
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
} else if !strings.Contains(err.Error(), "spec: Forbidden: pod updates may not change fields other than") {
|
||||||
|
t.Fatalf("Unexpected error when updating pod container resources: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = client.CoreV1().Pods(ns.Name).Resize(context.TODO(), resp.Name, resp, metav1.UpdateOptions{})
|
||||||
|
if tc.valid && err != nil {
|
||||||
|
t.Fatalf("Unexpected pod resize failure: %v", err)
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
if !tc.valid && err == nil {
|
||||||
|
t.Fatalf("Unexpected pod resize success")
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part 2. Rollback
|
||||||
|
if !tc.valid {
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp.Spec.Containers[0].Resources = tc.originalRes
|
||||||
|
_, err = client.CoreV1().Pods(ns.Name).Resize(context.TODO(), resp.Name, resp, metav1.UpdateOptions{})
|
||||||
|
if tc.valid && err != nil {
|
||||||
|
t.Fatalf("Unexpected pod resize failure: %v", err)
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
if !tc.valid && err == nil {
|
||||||
|
t.Fatalf("Unexpected pod resize success")
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
patchCases := []struct {
|
||||||
|
name string
|
||||||
|
originalRes v1.ResourceRequirements
|
||||||
|
patchBody string
|
||||||
|
patchType types.PatchType
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "cpu request change (strategic)",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("10m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patchType: types.StrategicMergePatchType,
|
||||||
|
patchBody: `{
|
||||||
|
"spec":{
|
||||||
|
"containers":[
|
||||||
|
{
|
||||||
|
"name":"fake-name",
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"cpu":"20m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cpu request change (merge)",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("10m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patchType: types.MergePatchType,
|
||||||
|
patchBody: `{
|
||||||
|
"spec":{
|
||||||
|
"containers":[
|
||||||
|
{
|
||||||
|
"name":"fake-name",
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"cpu":"20m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cpu request change (JSON)",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("10m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patchType: types.JSONPatchType,
|
||||||
|
patchBody: `[{
|
||||||
|
"op":"add",
|
||||||
|
"path":"/spec/containers",
|
||||||
|
"value":[{
|
||||||
|
"name":"fake-name",
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"cpu":"20m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]`,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "storage request change (merge)",
|
||||||
|
originalRes: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: resource.MustParse("10m"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
patchType: types.MergePatchType,
|
||||||
|
patchBody: `{
|
||||||
|
"spec":{
|
||||||
|
"containers":[
|
||||||
|
{
|
||||||
|
"name":"fake-name",
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"ephemeral-storage":"20m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range patchCases {
|
||||||
|
pod := testPod("resize")
|
||||||
|
pod.Spec.Containers[0].Resources = tc.originalRes
|
||||||
|
if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
|
||||||
|
t.Fatalf("Unexpected error when creating pod: %v", err)
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := client.CoreV1().Pods(ns.Name).Patch(context.TODO(), pod.Name, tc.patchType, []byte(tc.patchBody), metav1.PatchOptions{}, "resize"); tc.valid && err != nil {
|
||||||
|
t.Fatalf("Unexpected pod resize failure: %v", err)
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
} else if !tc.valid && err == nil {
|
||||||
|
t.Fatalf("Unexpected pod resize success")
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMutablePodSchedulingDirectives(t *testing.T) {
|
func TestMutablePodSchedulingDirectives(t *testing.T) {
|
||||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||||
server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd())
|
server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd())
|
||||||
|
@ -406,8 +406,8 @@ func TestCoreResourceEnqueue(t *testing.T) {
|
|||||||
triggerFn: func(testCtx *testutils.TestContext) (map[framework.ClusterEvent]uint64, error) {
|
triggerFn: func(testCtx *testutils.TestContext) (map[framework.ClusterEvent]uint64, error) {
|
||||||
// Trigger a PodUpdate event by reducing cpu requested by pod1.
|
// Trigger a PodUpdate event by reducing cpu requested by pod1.
|
||||||
// It makes Pod1 schedulable.
|
// It makes Pod1 schedulable.
|
||||||
if _, err := testCtx.ClientSet.CoreV1().Pods(testCtx.NS.Name).Update(testCtx.Ctx, st.MakePod().Name("pod1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "2"}).Container("image").Obj(), metav1.UpdateOptions{}); err != nil {
|
if _, err := testCtx.ClientSet.CoreV1().Pods(testCtx.NS.Name).Resize(testCtx.Ctx, "pod1", st.MakePod().Name("pod1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "2"}).Container("image").Obj(), metav1.UpdateOptions{}); err != nil {
|
||||||
return nil, fmt.Errorf("failed to update the pod: %w", err)
|
return nil, fmt.Errorf("failed to resize the pod: %w", err)
|
||||||
}
|
}
|
||||||
return map[framework.ClusterEvent]uint64{{Resource: unschedulablePod, ActionType: framework.UpdatePodScaleDown}: 1}, nil
|
return map[framework.ClusterEvent]uint64{{Resource: unschedulablePod, ActionType: framework.UpdatePodScaleDown}: 1}, nil
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user