Change:
[x] Original approval issue: - Reverted due to flakes [x] Two weeks soak end date: 20 November 2020 This issue is created to allow edit by /wip /hold According to this APIsnoop query, there are still some remaining Pod endpoints which are untested. a Pod with a static label the Pod with a new Label and updated data the Pod to ensure it's patched the Pod's status the Pod's status Ready condition to False the Pod's status to check if Ready is False all Pods in all Namespaces find the Pod(1) ensure that the Pod is found and is patched Namespaced Pod(1) via a Collection with a LabelSelector the Pod to check that it's deleted Discover useragents: List endpoints hit by the test: Display endpoint coverage change: If a test with these calls gets merged, test coverage will go up by 4 points This test is also created with the goal of conformance promotion. /sig testing /sig architecture /area conformance
/reopen Test PR Merge Promotion PR to be created next
Reopened this issue. <detailsIn response to : /reopen Test PR Merge Promotion PR to be created next Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
reverted by due to flaky test
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale
/reopen PR on test grid for 2 weeks before promotion to conformance
Reopened this issue. <detailsIn response to : /reopen PR on test grid for 2 weeks before promotion to conformance Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/triage accepted

Discussion:
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", <ins> "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", </ins> "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",

"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", <ins> "//staging/src/k8s.io/client-go/dynamic:go_default_library", </ins> "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/watch:go_default_library",

"golang.org/x/net/websocket" <ins> "encoding/json" </ins> v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" <ins> "k8s.io/apimachinery/pkg/runtime/schema" </ins> "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" <ins> "k8s.io/client-go/dynamic" </ins> "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" podutil "k8s.io/kubernetes/pkg/api/v1/pod"

maxBackOffTolerance  = time.Duration(1.3 * float64(kubelet.MaxContainerBackOff)) podRetryPeriod       = 1 * time.Second podRetryTimeout      = 1 * time.Minute <ins> podReadyTimeout      = 1 * time.Minute </ins> ) // testHostIP tests that a pod gets a host IP

var _ = framework.KubeDescribe("Pods", func() { f := framework.NewDefaultFramework("pods") var podClient *framework.PodClient <ins> var dc dynamic.Interface </ins> ginkgo.BeforeEach(func() { podClient = f.PodClient() <ins> dc = f.DynamicClient </ins> }) /*

err = wait.PollImmediate(podRetryPeriod, podRetryTimeout, checkPodListQuantity(f, "type=Testing", 0)) framework.ExpectNoError(err, "found a pod(s)") }) <ins> ginkgo.It("should run through the lifecycle of Pods and PodStatus", func() { podResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} testNamespaceName := f.Namespace.Name testPodName := "pod-test" testPodImage := imageutils.GetE2EImage(imageutils.Agnhost) testPodImage2 := imageutils.GetE2EImage(imageutils.Httpd) testPodLabels := map[string]string{"test-pod-static": "true"} testPodLabelsFlat := "test-pod-static=true" zero := int64(0) w := &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { options.LabelSelector = testPodLabelsFlat return f.ClientSet.CoreV1().Pods(testNamespaceName).Watch(context.TODO(), options) }, } podsList, err := f.ClientSet.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{LabelSelector: testPodLabelsFlat}) framework.ExpectNoError(err, "failed to list Pods") testPod := v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:   testPodName, Labels: testPodLabels, }, Spec: v1.PodSpec{ TerminationGracePeriodSeconds: &zero, Containers: []v1.Container{ { Name:  testPodName, Image: testPodImage, }, }, }, } ginkgo.By("creating a Pod with a static label") _, err = f.ClientSet.CoreV1().Pods(testNamespaceName).Create(context.TODO(), &testPod, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create Pod %v in namespace %v", testPod.ObjectMeta.Name, testNamespaceName) ginkgo.By("watching for Pod to be ready") ctx, cancel := context.WithTimeout(context.Background(), podReadyTimeout) defer cancel() _, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) { if pod, ok := event.Object.(*v1.Pod); ok { found := pod.ObjectMeta.Name == testPod.ObjectMeta.Name && pod.ObjectMeta.Namespace == testNamespaceName && pod.Labels["test-pod-static"] == "true" && pod.Status.Phase == v1.PodRunning if !found { framework.Logf("observed Pod %v in namespace %v in phase %v conditions %v", pod.ObjectMeta.Name, pod.ObjectMeta.Namespace, pod.Status.Phase, pod.Status.Conditions) } return found, nil } return false, nil }) framework.ExpectNoError(err, "failed to see Pod %v in namespace %v running", testPod.ObjectMeta.Name, testNamespaceName) ginkgo.By("patching the Pod with a new Label and updated data") podPatch, err := json.Marshal(v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{"test-pod": "patched"}, }, Spec: v1.PodSpec{ TerminationGracePeriodSeconds: &zero, Containers: []v1.Container{{ Name:  testPodName, Image: testPodImage2, }}, }, }) framework.ExpectNoError(err, "failed to marshal JSON patch for Pod") _, err = f.ClientSet.CoreV1().Pods(testNamespaceName).Patch(context.TODO(), testPodName, types.StrategicMergePatchType, []byte(podPatch), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch Pod %s in namespace %s", testPodName, testNamespaceName) ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) defer cancel() _, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) { switch event.Type { case watch.Modified: if pod, ok := event.Object.(*v1.Pod); ok { found := pod.ObjectMeta.Name == pod.Name && pod.Labels["test-pod-static"] == "true" return found, nil } default: framework.Logf("observed event type %v", event.Type) } return false, nil }) framework.ExpectNoError(err, "failed to see %v event", watch.Modified) ginkgo.By("getting the Pod and ensuring that it's patched") pod, err := f.ClientSet.CoreV1().Pods(testNamespaceName).Get(context.TODO(), testPodName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to fetch Pod %s in namespace %s", testPodName, testNamespaceName) framework.ExpectEqual(pod.ObjectMeta.Labels["test-pod"], "patched", "failed to patch Pod - missing label") framework.ExpectEqual(pod.Spec.Containers[0].Image, testPodImage2, "failed to patch Pod - wrong image") ginkgo.By("getting the PodStatus") podStatusUnstructured, err := dc.Resource(podResource).Namespace(testNamespaceName).Get(context.TODO(), testPodName, metav1.GetOptions{}, "status") framework.ExpectNoError(err, "failed to fetch PodStatus of Pod %s in namespace %s", testPodName, testNamespaceName) podStatusBytes, err := json.Marshal(podStatusUnstructured) framework.ExpectNoError(err, "failed to marshal unstructured response") var podStatus v1.Pod err = json.Unmarshal(podStatusBytes, &podStatus) framework.ExpectNoError(err, "failed to unmarshal JSON bytes to a Pod object type") ginkgo.By("replacing the Pod's status Ready condition to False") podStatusUpdated := podStatus podStatusFieldPatchCount := 0 podStatusFieldPatchCountTotal := 2 for pos, cond := range podStatusUpdated.Status.Conditions { if (cond.Type == v1.PodReady && cond.Status == v1.ConditionTrue) || (cond.Type == v1.ContainersReady && cond.Status == v1.ConditionTrue) { podStatusUpdated.Status.Conditions[pos].Status = v1.ConditionFalse podStatusFieldPatchCount++ } } framework.ExpectEqual(podStatusFieldPatchCount, podStatusFieldPatchCountTotal, "failed to patch all relevant Pod conditions") podStatusUpdate, err := f.ClientSet.CoreV1().Pods(testNamespaceName).UpdateStatus(context.TODO(), &podStatusUpdated, metav1.UpdateOptions{}) framework.ExpectNoError(err, "failed to update PodStatus of Pod %s in namespace %s", testPodName, testNamespaceName) ginkgo.By("check the Pod again to ensure its Ready conditions are False") podStatusFieldPatchCount = 0 podStatusFieldPatchCountTotal = 2 for _, cond := range podStatusUpdate.Status.Conditions { if (cond.Type == v1.PodReady && cond.Status == v1.ConditionFalse) || (cond.Type == v1.ContainersReady && cond.Status == v1.ConditionFalse) { podStatusFieldPatchCount++ } } framework.ExpectEqual(podStatusFieldPatchCount, podStatusFieldPatchCountTotal, "failed to update PodStatus - field patch count doesn't match the total") ginkgo.By("deleting the Pod via a Collection with a LabelSelector") err = f.ClientSet.CoreV1().Pods(testNamespaceName).DeleteCollection(context.TODO(), metav1.DeleteOptions{GracePeriodSeconds: &zero}, metav1.ListOptions{LabelSelector: testPodLabelsFlat}) framework.ExpectNoError(err, "failed to delete Pod by collection") ginkgo.By("watching for the Pod to be deleted") ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() _, err = watchtools.Until(ctx, podsList.ResourceVersion, w, func(event watch.Event) (bool, error) { switch event.Type { case watch.Deleted: if pod, ok := event.Object.(*v1.Pod); ok { found := pod.ObjectMeta.Name == pod.Name && pod.Labels["test-pod-static"] == "true" return found, nil } default: framework.Logf("observed event type %v", event.Type) } return false, nil }) framework.ExpectNoError(err, "failed to see %v event", watch.Deleted) }) </ins> }) func checkPodListQuantity(f *framework.Framework, label string, quantity int) func() (bool, error) {