Skip to content

Commit 8e5c022

Browse files
authored
Merge pull request kubernetes#90942 from ii/ii-create-pod%2Bpodstatus-resource-lifecycle-test
Create Pod+PodStatus resource lifecycle test - +4 endpoint coverage
2 parents 1ed2cf1 + 642bed3 commit 8e5c022

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

test/e2e/common/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ go_library(
5858
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
5959
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
6060
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
61+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
6162
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
6263
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
6364
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
@@ -66,6 +67,7 @@ go_library(
6667
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
6768
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
6869
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
70+
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
6971
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
7072
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
7173
"//staging/src/k8s.io/client-go/tools/watch:go_default_library",

test/e2e/common/pods.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ package common
1919
import (
2020
"bytes"
2121
"context"
22+
"encoding/json"
2223
"fmt"
2324
"io"
25+
"k8s.io/apimachinery/pkg/runtime/schema"
26+
"k8s.io/client-go/dynamic"
2427
"runtime/debug"
2528
"strconv"
2629
"strings"
@@ -177,9 +180,11 @@ func expectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interf
177180

178181
var _ = framework.KubeDescribe("Pods", func() {
179182
f := framework.NewDefaultFramework("pods")
183+
var dc dynamic.Interface
180184
var podClient *framework.PodClient
181185
ginkgo.BeforeEach(func() {
182186
podClient = f.PodClient()
187+
dc = f.DynamicClient
183188
})
184189

185190
/*
@@ -870,6 +875,154 @@ var _ = framework.KubeDescribe("Pods", func() {
870875
err = wait.PollImmediate(podRetryPeriod, podRetryTimeout, checkPodListQuantity(f, "type=Testing", 0))
871876
framework.ExpectNoError(err, "found a pod(s)")
872877
})
878+
879+
ginkgo.It("should run through the lifecycle of Pods and PodStatus", func() {
880+
podResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
881+
testNamespaceName := f.Namespace.Name
882+
testPodName := "pod-test"
883+
testPodImage := imageutils.GetE2EImage(imageutils.Agnhost)
884+
testPodImage2 := imageutils.GetE2EImage(imageutils.Httpd)
885+
testPodLabels := map[string]string{"test-pod-static": "true"}
886+
testPodLabelsFlat := "test-pod-static=true"
887+
888+
w := &cache.ListWatch{
889+
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
890+
options.LabelSelector = testPodLabelsFlat
891+
return f.ClientSet.CoreV1().Pods(testNamespaceName).Watch(context.TODO(), options)
892+
},
893+
}
894+
podsList, err := f.ClientSet.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{LabelSelector: testPodLabelsFlat})
895+
framework.ExpectNoError(err, "failed to list Pods")
896+
897+
testPod := v1.Pod{
898+
ObjectMeta: metav1.ObjectMeta{
899+
Name: testPodName,
900+
Labels: testPodLabels,
901+
},
902+
Spec: v1.PodSpec{
903+
Containers: []v1.Container{
904+
{
905+
Name: testPodName,
906+
Image: testPodImage,
907+
},
908+
},
909+
},
910+
}
911+
ginkgo.By("creating a Pod with a static label")
912+
_, err = f.ClientSet.CoreV1().Pods(testNamespaceName).Create(context.TODO(), &testPod, metav1.CreateOptions{})
913+
framework.ExpectNoError(err, "failed to create Pod %v in namespace %v", testPod.ObjectMeta.Name, testNamespaceName)
914+
915+
ginkgo.By("watching for Pod to be ready")
916+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
917+
defer cancel()
918+
_, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) {
919+
if pod, ok := event.Object.(*v1.Pod); ok {
920+
found := pod.ObjectMeta.Name == testPod.ObjectMeta.Name &&
921+
pod.ObjectMeta.Namespace == testNamespaceName &&
922+
pod.Labels["test-pod-static"] == "true" &&
923+
pod.Status.Phase == v1.PodRunning
924+
if !found {
925+
framework.Logf("observed Pod %v in namespace %v in phase %v", pod.ObjectMeta.Name, pod.ObjectMeta.Namespace, pod.Status.Phase)
926+
}
927+
return found, nil
928+
}
929+
return false, nil
930+
})
931+
framework.ExpectNoError(err, "failed to see Pod %v in namespace %v running", testPod.ObjectMeta.Name, testNamespaceName)
932+
933+
ginkgo.By("patching the Pod with a new Label and updated data")
934+
podPatch, err := json.Marshal(v1.Pod{
935+
ObjectMeta: metav1.ObjectMeta{
936+
Labels: map[string]string{"test-pod": "patched"},
937+
},
938+
Spec: v1.PodSpec{
939+
Containers: []v1.Container{{
940+
Name: testPodName,
941+
Image: testPodImage2,
942+
}},
943+
},
944+
})
945+
framework.ExpectNoError(err, "failed to marshal JSON patch for Pod")
946+
_, err = f.ClientSet.CoreV1().Pods(testNamespaceName).Patch(context.TODO(), testPodName, types.StrategicMergePatchType, []byte(podPatch), metav1.PatchOptions{})
947+
framework.ExpectNoError(err, "failed to patch Pod %s in namespace %s", testPodName, testNamespaceName)
948+
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
949+
defer cancel()
950+
_, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) {
951+
switch event.Type {
952+
case watch.Modified:
953+
if pod, ok := event.Object.(*v1.Pod); ok {
954+
found := pod.ObjectMeta.Name == pod.Name &&
955+
pod.Labels["test-pod-static"] == "true"
956+
return found, nil
957+
}
958+
default:
959+
framework.Logf("observed event type %v", event.Type)
960+
}
961+
return false, nil
962+
})
963+
framework.ExpectNoError(err, "failed to see %v event", watch.Modified)
964+
965+
ginkgo.By("getting the Pod and ensuring that it's patched")
966+
pod, err := f.ClientSet.CoreV1().Pods(testNamespaceName).Get(context.TODO(), testPodName, metav1.GetOptions{})
967+
framework.ExpectNoError(err, "failed to fetch Pod %s in namespace %s", testPodName, testNamespaceName)
968+
framework.ExpectEqual(pod.ObjectMeta.Labels["test-pod"], "patched", "failed to patch Pod - missing label")
969+
framework.ExpectEqual(pod.Spec.Containers[0].Image, testPodImage2, "failed to patch Pod - wrong image")
970+
971+
ginkgo.By("getting the PodStatus")
972+
podStatusUnstructured, err := dc.Resource(podResource).Namespace(testNamespaceName).Get(context.TODO(), testPodName, metav1.GetOptions{}, "status")
973+
framework.ExpectNoError(err, "failed to fetch PodStatus of Pod %s in namespace %s", testPodName, testNamespaceName)
974+
podStatusBytes, err := json.Marshal(podStatusUnstructured)
975+
framework.ExpectNoError(err, "failed to marshal unstructured response")
976+
var podStatus v1.Pod
977+
err = json.Unmarshal(podStatusBytes, &podStatus)
978+
framework.ExpectNoError(err, "failed to unmarshal JSON bytes to a Pod object type")
979+
980+
ginkgo.By("replacing the Pod's status Ready condition to False")
981+
podStatusUpdated := podStatus
982+
podStatusFieldPatchCount := 0
983+
podStatusFieldPatchCountTotal := 2
984+
for pos, cond := range podStatusUpdated.Status.Conditions {
985+
if (cond.Type == v1.PodReady && cond.Status == v1.ConditionTrue) || (cond.Type == v1.ContainersReady && cond.Status == v1.ConditionTrue) {
986+
podStatusUpdated.Status.Conditions[pos].Status = v1.ConditionFalse
987+
podStatusFieldPatchCount++
988+
}
989+
}
990+
framework.ExpectEqual(podStatusFieldPatchCount, podStatusFieldPatchCountTotal, "failed to patch all relevant Pod conditions")
991+
podStatusUpdate, err := f.ClientSet.CoreV1().Pods(testNamespaceName).UpdateStatus(context.TODO(), &podStatusUpdated, metav1.UpdateOptions{})
992+
framework.ExpectNoError(err, "failed to update PodStatus of Pod %s in namespace %s", testPodName, testNamespaceName)
993+
994+
ginkgo.By("check the Pod again to ensure its Ready conditions are False")
995+
podStatusFieldPatchCount = 0
996+
podStatusFieldPatchCountTotal = 2
997+
for _, cond := range podStatusUpdate.Status.Conditions {
998+
if (cond.Type == v1.PodReady && cond.Status == v1.ConditionFalse) || (cond.Type == v1.ContainersReady && cond.Status == v1.ConditionFalse) {
999+
podStatusFieldPatchCount++
1000+
}
1001+
}
1002+
framework.ExpectEqual(podStatusFieldPatchCount, podStatusFieldPatchCountTotal, "failed to update PodStatus - field patch count doesn't match the total")
1003+
1004+
ginkgo.By("deleting the Pod via a Collection with a LabelSelector")
1005+
err = f.ClientSet.CoreV1().Pods(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: testPodLabelsFlat})
1006+
framework.ExpectNoError(err, "failed to delete Pod by collection")
1007+
1008+
ginkgo.By("watching for the Pod to be deleted")
1009+
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
1010+
defer cancel()
1011+
_, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) {
1012+
switch event.Type {
1013+
case watch.Deleted:
1014+
if pod, ok := event.Object.(*v1.Pod); ok {
1015+
found := pod.ObjectMeta.Name == pod.Name &&
1016+
pod.Labels["test-pod-static"] == "true"
1017+
return found, nil
1018+
}
1019+
default:
1020+
framework.Logf("observed event type %v", event.Type)
1021+
}
1022+
return false, nil
1023+
})
1024+
framework.ExpectNoError(err, "failed to see %v event", watch.Deleted)
1025+
})
8731026
})
8741027

8751028
func checkPodListQuantity(f *framework.Framework, label string, quantity int) func() (bool, error) {

0 commit comments

Comments
 (0)