@@ -19,8 +19,11 @@ package common
19
19
import (
20
20
"bytes"
21
21
"context"
22
+ "encoding/json"
22
23
"fmt"
23
24
"io"
25
+ "k8s.io/apimachinery/pkg/runtime/schema"
26
+ "k8s.io/client-go/dynamic"
24
27
"runtime/debug"
25
28
"strconv"
26
29
"strings"
@@ -177,9 +180,11 @@ func expectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interf
177
180
178
181
var _ = framework .KubeDescribe ("Pods" , func () {
179
182
f := framework .NewDefaultFramework ("pods" )
183
+ var dc dynamic.Interface
180
184
var podClient * framework.PodClient
181
185
ginkgo .BeforeEach (func () {
182
186
podClient = f .PodClient ()
187
+ dc = f .DynamicClient
183
188
})
184
189
185
190
/*
@@ -870,6 +875,154 @@ var _ = framework.KubeDescribe("Pods", func() {
870
875
err = wait .PollImmediate (podRetryPeriod , podRetryTimeout , checkPodListQuantity (f , "type=Testing" , 0 ))
871
876
framework .ExpectNoError (err , "found a pod(s)" )
872
877
})
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
+ })
873
1026
})
874
1027
875
1028
func checkPodListQuantity (f * framework.Framework , label string , quantity int ) func () (bool , error ) {
0 commit comments