func NewPodGC(kubeClient clientset.Interface, podInformer cache.SharedIndexInformer, terminatedPodThreshold int) *PodGCController { if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } gcc := &PodGCController{ kubeClient: kubeClient, terminatedPodThreshold: terminatedPodThreshold, deletePod: func(namespace, name string) error { glog.Infof("PodGC is force deleting Pod: %v:%v", namespace, name) return kubeClient.Core().Pods(namespace).Delete(name, v1.NewDeleteOptions(0)) }, } gcc.podStore.Indexer = podInformer.GetIndexer() gcc.podController = podInformer.GetController() gcc.nodeStore.Store, gcc.nodeController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return gcc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return gcc.kubeClient.Core().Nodes().Watch(options) }, }, &v1.Node{}, controller.NoResyncPeriodFunc(), cache.ResourceEventHandlerFuncs{}, ) return gcc }
func validateTargetedProbeOutput(f *framework.Framework, pod *v1.Pod, fileNames []string, value string) { By("submitting the pod to kubernetes") podClient := f.ClientSet.Core().Pods(f.Namespace.Name) defer func() { By("deleting the pod") defer GinkgoRecover() podClient.Delete(pod.Name, v1.NewDeleteOptions(0)) }() if _, err := podClient.Create(pod); err != nil { framework.Failf("Failed to create %s pod: %v", pod.Name, err) } framework.ExpectNoError(f.WaitForPodRunning(pod.Name)) By("retrieving the pod") pod, err := podClient.Get(pod.Name) if err != nil { framework.Failf("Failed to get pod %s: %v", pod.Name, err) } // Try to find the expected value for each expected name. By("looking for the results for each expected name from probers") assertFilesContain(fileNames, "results", pod, f.ClientSet, true, value) framework.Logf("DNS probes using %s succeeded\n", pod.Name) }
func deleteServiceOrFail(clientset *fedclientset.Clientset, namespace string, serviceName string) { if clientset == nil || len(namespace) == 0 || len(serviceName) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to deleteServiceOrFail: clientset: %v, namespace: %v, service: %v", clientset, namespace, serviceName)) } err := clientset.Services(namespace).Delete(serviceName, v1.NewDeleteOptions(0)) framework.ExpectNoError(err, "Error deleting service %q from namespace %q", serviceName, namespace) }
// TODO: quinton: This is largely a cut 'n paste of the above. Yuck! Refactor as soon as we have a common interface implmented by both fedclientset.Clientset and kubeclientset.Clientset func deleteClusterIngressOrFail(clusterName string, clientset *kubeclientset.Clientset, namespace string, ingressName string) { if clientset == nil || len(namespace) == 0 || len(ingressName) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to deleteClusterIngressOrFail: cluster: %q, clientset: %v, namespace: %v, ingress: %v", clusterName, clientset, namespace, ingressName)) } err := clientset.Ingresses(namespace).Delete(ingressName, v1.NewDeleteOptions(0)) framework.ExpectNoError(err, "Error deleting cluster ingress %q/%q from cluster %q", namespace, ingressName, clusterName) }
func (t *dnsConfigMapTest) deleteUtilPod() { podClient := t.c.Core().Pods(t.f.Namespace.Name) if err := podClient.Delete(t.utilPod.Name, v1.NewDeleteOptions(0)); err != nil { framework.Logf("Delete of pod %v:%v failed: %v", t.utilPod.Namespace, t.utilPod.Name, err) } }
func runLivenessTest(f *framework.Framework, pod *v1.Pod, expectNumRestarts int, timeout time.Duration) { podClient := f.PodClient() ns := f.Namespace.Name Expect(pod.Spec.Containers).NotTo(BeEmpty()) containerName := pod.Spec.Containers[0].Name // At the end of the test, clean up by removing the pod. defer func() { By("deleting the pod") podClient.Delete(pod.Name, v1.NewDeleteOptions(0)) }() By(fmt.Sprintf("Creating pod %s in namespace %s", pod.Name, ns)) podClient.Create(pod) // Wait until the pod is not pending. (Here we need to check for something other than // 'Pending' other than checking for 'Running', since when failures occur, we go to // 'Terminated' which can cause indefinite blocking.) framework.ExpectNoError(framework.WaitForPodNotPending(f.ClientSet, ns, pod.Name, pod.ResourceVersion), fmt.Sprintf("starting pod %s in namespace %s", pod.Name, ns)) framework.Logf("Started pod %s in namespace %s", pod.Name, ns) // Check the pod's current state and verify that restartCount is present. By("checking the pod's current state and verifying that restartCount is present") pod, err := podClient.Get(pod.Name, metav1.GetOptions{}) framework.ExpectNoError(err, fmt.Sprintf("getting pod %s in namespace %s", pod.Name, ns)) initialRestartCount := v1.GetExistingContainerStatus(pod.Status.ContainerStatuses, containerName).RestartCount framework.Logf("Initial restart count of pod %s is %d", pod.Name, initialRestartCount) // Wait for the restart state to be as desired. deadline := time.Now().Add(timeout) lastRestartCount := initialRestartCount observedRestarts := int32(0) for start := time.Now(); time.Now().Before(deadline); time.Sleep(2 * time.Second) { pod, err = podClient.Get(pod.Name, metav1.GetOptions{}) framework.ExpectNoError(err, fmt.Sprintf("getting pod %s", pod.Name)) restartCount := v1.GetExistingContainerStatus(pod.Status.ContainerStatuses, containerName).RestartCount if restartCount != lastRestartCount { framework.Logf("Restart count of pod %s/%s is now %d (%v elapsed)", ns, pod.Name, restartCount, time.Since(start)) if restartCount < lastRestartCount { framework.Failf("Restart count should increment monotonically: restart cont of pod %s/%s changed from %d to %d", ns, pod.Name, lastRestartCount, restartCount) } } observedRestarts = restartCount - initialRestartCount if expectNumRestarts > 0 && int(observedRestarts) >= expectNumRestarts { // Stop if we have observed more than expectNumRestarts restarts. break } lastRestartCount = restartCount } // If we expected 0 restarts, fail if observed any restart. // If we expected n restarts (n > 0), fail if we observed < n restarts. if (expectNumRestarts == 0 && observedRestarts > 0) || (expectNumRestarts > 0 && int(observedRestarts) < expectNumRestarts) { framework.Failf("pod %s/%s - expected number of restarts: %d, found restarts: %d", ns, pod.Name, expectNumRestarts, observedRestarts) } }
// syncPod syncs the given status with the API server. The caller must not hold the lock. func (m *manager) syncPod(uid types.UID, status versionedPodStatus) { if !m.needsUpdate(uid, status) { glog.V(1).Infof("Status for pod %q is up-to-date; skipping", uid) return } // TODO: make me easier to express from client code pod, err := m.kubeClient.Core().Pods(status.podNamespace).Get(status.podName, metav1.GetOptions{}) if errors.IsNotFound(err) { glog.V(3).Infof("Pod %q (%s) does not exist on the server", status.podName, uid) // If the Pod is deleted the status will be cleared in // RemoveOrphanedStatuses, so we just ignore the update here. return } if err == nil { translatedUID := m.podManager.TranslatePodUID(pod.UID) if len(translatedUID) > 0 && translatedUID != uid { glog.V(2).Infof("Pod %q was deleted and then recreated, skipping status update; old UID %q, new UID %q", format.Pod(pod), uid, translatedUID) m.deletePodStatus(uid) return } pod.Status = status.status if err := podutil.SetInitContainersStatusesAnnotations(pod); err != nil { glog.Error(err) } // TODO: handle conflict as a retry, make that easier too. pod, err = m.kubeClient.Core().Pods(pod.Namespace).UpdateStatus(pod) if err == nil { glog.V(3).Infof("Status for pod %q updated successfully: %+v", format.Pod(pod), status) m.apiStatusVersions[pod.UID] = status.version if kubepod.IsMirrorPod(pod) { // We don't handle graceful deletion of mirror pods. return } if pod.DeletionTimestamp == nil { return } if !notRunning(pod.Status.ContainerStatuses) { glog.V(3).Infof("Pod %q is terminated, but some containers are still running", format.Pod(pod)) return } deleteOptions := v1.NewDeleteOptions(0) // Use the pod UID as the precondition for deletion to prevent deleting a newly created pod with the same name and namespace. deleteOptions.Preconditions = v1.NewUIDPreconditions(string(pod.UID)) if err = m.kubeClient.Core().Pods(pod.Namespace).Delete(pod.Name, deleteOptions); err == nil { glog.V(3).Infof("Pod %q fully terminated and removed from etcd", format.Pod(pod)) m.deletePodStatus(uid) return } } } // We failed to update status, wait for periodic sync to retry. glog.Warningf("Failed to update status for pod %q: %v", format.Pod(pod), err) }
/* deleteOneBackendPodOrFail deletes exactly one backend pod which must not be nil The test fails if there are any errors. */ func deleteOneBackendPodOrFail(c *cluster) { pod := c.backendPod Expect(pod).ToNot(BeNil()) err := c.Clientset.Core().Pods(pod.Namespace).Delete(pod.Name, v1.NewDeleteOptions(0)) if errors.IsNotFound(err) { By(fmt.Sprintf("Pod %q in namespace %q in cluster %q does not exist. No need to delete it.", pod.Name, pod.Namespace, c.name)) } else { framework.ExpectNoError(err, "Deleting pod %q in namespace %q from cluster %q", pod.Name, pod.Namespace, c.name) } By(fmt.Sprintf("Backend pod %q in namespace %q in cluster %q deleted or does not exist", pod.Name, pod.Namespace, c.name)) }
func runPodAndGetNodeName(f *framework.Framework, conf pausePodConfig) string { // launch a pod to find a node which can launch a pod. We intentionally do // not just take the node list and choose the first of them. Depending on the // cluster and the scheduler it might be that a "normal" pod cannot be // scheduled onto it. pod := runPausePod(f, conf) By("Explicitly delete pod here to free the resource it takes.") err := f.ClientSet.Core().Pods(f.Namespace.Name).Delete(pod.Name, v1.NewDeleteOptions(0)) framework.ExpectNoError(err) return pod.Spec.NodeName }
func (mc *basicMirrorClient) DeleteMirrorPod(podFullName string) error { if mc.apiserverClient == nil { return nil } name, namespace, err := kubecontainer.ParsePodFullName(podFullName) if err != nil { glog.Errorf("Failed to parse a pod full name %q", podFullName) return err } glog.V(2).Infof("Deleting a mirror pod %q", podFullName) // TODO(random-liu): Delete the mirror pod with uid precondition in mirror pod manager if err := mc.apiserverClient.Core().Pods(namespace).Delete(name, v1.NewDeleteOptions(0)); err != nil && !errors.IsNotFound(err) { glog.Errorf("Failed deleting a mirror pod %q: %v", podFullName, err) } return nil }
// deletePodsSync deletes a list of pods and block until pods disappear. func deletePodsSync(f *framework.Framework, pods []*v1.Pod) { var wg sync.WaitGroup for _, pod := range pods { wg.Add(1) go func(pod *v1.Pod) { defer wg.Done() err := f.PodClient().Delete(pod.ObjectMeta.Name, v1.NewDeleteOptions(30)) Expect(err).NotTo(HaveOccurred()) Expect(framework.WaitForPodToDisappear(f.ClientSet, f.Namespace.Name, pod.ObjectMeta.Name, labels.Everything(), 30*time.Second, 10*time.Minute)).NotTo(HaveOccurred()) }(pod) } wg.Wait() return }
func (config *NetworkingTestConfig) DeleteNetProxyPod() { pod := config.EndpointPods[0] config.getPodClient().Delete(pod.Name, v1.NewDeleteOptions(0)) config.EndpointPods = config.EndpointPods[1:] // wait for pod being deleted. err := WaitForPodToDisappear(config.f.ClientSet, config.Namespace, pod.Name, labels.Everything(), time.Second, wait.ForeverTestTimeout) if err != nil { Failf("Failed to delete %s pod: %v", pod.Name, err) } // wait for endpoint being removed. err = WaitForServiceEndpointsNum(config.f.ClientSet, config.Namespace, nodePortServiceName, len(config.EndpointPods), time.Second, wait.ForeverTestTimeout) if err != nil { Failf("Failed to remove endpoint from service: %s", nodePortServiceName) } // wait for kube-proxy to catch up with the pod being deleted. time.Sleep(5 * time.Second) }
func discoverService(f *framework.Framework, name string, exists bool, podName string) { command := []string{"sh", "-c", fmt.Sprintf("until nslookup '%s'; do sleep 10; done", name)} By(fmt.Sprintf("Looking up %q", name)) pod := &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Name: podName, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name: "federated-service-discovery-container", Image: "gcr.io/google_containers/busybox:1.24", Command: command, }, }, RestartPolicy: v1.RestartPolicyOnFailure, }, } nsName := f.FederationNamespace.Name By(fmt.Sprintf("Creating pod %q in namespace %q", pod.Name, nsName)) _, err := f.ClientSet.Core().Pods(nsName).Create(pod) framework.ExpectNoError(err, "Trying to create pod to run %q", command) By(fmt.Sprintf("Successfully created pod %q in namespace %q", pod.Name, nsName)) defer func() { By(fmt.Sprintf("Deleting pod %q from namespace %q", podName, nsName)) err := f.ClientSet.Core().Pods(nsName).Delete(podName, v1.NewDeleteOptions(0)) framework.ExpectNoError(err, "Deleting pod %q from namespace %q", podName, nsName) By(fmt.Sprintf("Deleted pod %q from namespace %q", podName, nsName)) }() if exists { // TODO(mml): Eventually check the IP address is correct, too. Eventually(podExitCodeDetector(f, podName, nsName, 0), 3*DNSTTL, time.Second*2). Should(BeNil(), "%q should exit 0, but it never did", command) } else { Eventually(podExitCodeDetector(f, podName, nsName, 0), 3*DNSTTL, time.Second*2). ShouldNot(BeNil(), "%q should eventually not exit 0, but it always did", command) } }
func checkExistingRCRecovers(f *framework.Framework) { By("assert that the pre-existing replication controller recovers") podClient := f.ClientSet.Core().Pods(f.Namespace.Name) rcSelector := labels.Set{"name": "baz"}.AsSelector() By("deleting pods from existing replication controller") framework.ExpectNoError(wait.Poll(time.Millisecond*500, time.Second*60, func() (bool, error) { options := v1.ListOptions{LabelSelector: rcSelector.String()} pods, err := podClient.List(options) if err != nil { framework.Logf("apiserver returned error, as expected before recovery: %v", err) return false, nil } if len(pods.Items) == 0 { return false, nil } for _, pod := range pods.Items { err = podClient.Delete(pod.Name, v1.NewDeleteOptions(0)) Expect(err).NotTo(HaveOccurred()) } framework.Logf("apiserver has recovered") return true, nil })) By("waiting for replication controller to recover") framework.ExpectNoError(wait.Poll(time.Millisecond*500, time.Second*60, func() (bool, error) { options := v1.ListOptions{LabelSelector: rcSelector.String()} pods, err := podClient.List(options) Expect(err).NotTo(HaveOccurred()) for _, pod := range pods.Items { if pod.DeletionTimestamp == nil && v1.IsPodReady(&pod) { return true, nil } } return false, nil })) }
func createGitServer(f *framework.Framework) (gitURL string, gitRepo string, cleanup func()) { var err error gitServerPodName := "git-server-" + string(uuid.NewUUID()) containerPort := 8000 labels := map[string]string{"name": gitServerPodName} gitServerPod := &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Name: gitServerPodName, Labels: labels, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name: "git-repo", Image: "gcr.io/google_containers/fakegitserver:0.1", ImagePullPolicy: "IfNotPresent", Ports: []v1.ContainerPort{ {ContainerPort: int32(containerPort)}, }, }, }, }, } f.PodClient().CreateSync(gitServerPod) // Portal IP and port httpPort := 2345 gitServerSvc := &v1.Service{ ObjectMeta: v1.ObjectMeta{ Name: "git-server-svc", }, Spec: v1.ServiceSpec{ Selector: labels, Ports: []v1.ServicePort{ { Name: "http-portal", Port: int32(httpPort), TargetPort: intstr.FromInt(containerPort), }, }, }, } if gitServerSvc, err = f.ClientSet.Core().Services(f.Namespace.Name).Create(gitServerSvc); err != nil { framework.Failf("unable to create test git server service %s: %v", gitServerSvc.Name, err) } return "http://" + gitServerSvc.Spec.ClusterIP + ":" + strconv.Itoa(httpPort), "test", func() { By("Cleaning up the git server pod") if err := f.ClientSet.Core().Pods(f.Namespace.Name).Delete(gitServerPod.Name, v1.NewDeleteOptions(0)); err != nil { framework.Failf("unable to delete git server pod %v: %v", gitServerPod.Name, err) } By("Cleaning up the git server svc") if err := f.ClientSet.Core().Services(f.Namespace.Name).Delete(gitServerSvc.Name, nil); err != nil { framework.Failf("unable to delete git server svc %v: %v", gitServerSvc.Name, err) } } }
} pods, err = podClient.List(options) if err != nil { framework.Failf("Failed to query for pods: %v", err) } Expect(len(pods.Items)).To(Equal(1)) By("verifying pod creation was observed") observeCreation(w) // We need to wait for the pod to be scheduled, otherwise the deletion // will be carried out immediately rather than gracefully. framework.ExpectNoError(f.WaitForPodRunning(pod.Name)) By("deleting the pod gracefully") if err := podClient.Delete(pod.Name, v1.NewDeleteOptions(30)); err != nil { framework.Failf("Failed to delete pod: %v", err) } By("verifying pod deletion was observed") obj := observeObjectDeletion(w) lastPod := obj.(*v1.Pod) Expect(lastPod.DeletionTimestamp).ToNot(BeNil()) Expect(lastPod.Spec.TerminationGracePeriodSeconds).ToNot(BeZero()) options = v1.ListOptions{LabelSelector: selector} pods, err = podClient.List(options) if err != nil { framework.Failf("Failed to list pods to verify deletion: %v", err) } Expect(len(pods.Items)).To(Equal(0))
func deleteV1Job(c clientset.Interface, ns, name string) error { return c.Batch().Jobs(ns).Delete(name, v1.NewDeleteOptions(0)) }
It("should schedule a pod w/ a RW PD, ungracefully remove it, then schedule it on another host [Slow]", func() { framework.SkipUnlessProviderIs("gce", "gke", "aws") By("creating PD") diskName, err := createPDWithRetry() framework.ExpectNoError(err, "Error creating PD") host0Pod := testPDPod([]string{diskName}, host0Name, false /* readOnly */, 1 /* numContainers */) host1Pod := testPDPod([]string{diskName}, host1Name, false /* readOnly */, 1 /* numContainers */) containerName := "mycontainer" defer func() { // Teardown pods, PD. Ignore errors. // Teardown should do nothing unless test failed. By("cleaning up PD-RW test environment") podClient.Delete(host0Pod.Name, v1.NewDeleteOptions(0)) podClient.Delete(host1Pod.Name, v1.NewDeleteOptions(0)) detachAndDeletePDs(diskName, []types.NodeName{host0Name, host1Name}) }() By("submitting host0Pod to kubernetes") _, err = podClient.Create(host0Pod) framework.ExpectNoError(err, fmt.Sprintf("Failed to create host0Pod: %v", err)) framework.ExpectNoError(f.WaitForPodRunningSlow(host0Pod.Name)) testFile := "/testpd1/tracker" testFileContents := fmt.Sprintf("%v", mathrand.Int()) framework.ExpectNoError(f.WriteFileViaContainer(host0Pod.Name, containerName, testFile, testFileContents)) framework.Logf("Wrote value: %v", testFileContents)
framework.Failf("failed to list with no objects: %v", err) } if err := json.Unmarshal(data, &list); err != nil { framework.Failf("failed to decode: %#v", err) } if len(list.Items) != 1 { framework.Failf("unexpected object too few or too many: %v", list) } if list.Items[0].Name != foo.Name || list.Items[0].SomeField != foo.SomeField || list.Items[0].OtherField != foo.OtherField { framework.Failf("expected: %#v, saw in list: %#v", foo, list.Items[0]) } // Need to manually do the serialization because otherwise the // Content-Type header is set to protobuf, the thirdparty codec in // the API server side only accepts JSON. deleteOptionsData, err := json.Marshal(v1.NewDeleteOptions(10)) framework.ExpectNoError(err) if _, err := f.ClientSet.Core().RESTClient().Delete(). AbsPath("/apis/company.com/v1/namespaces/default/foos/foo"). Body(deleteOptionsData). DoRaw(); err != nil { framework.Failf("failed to delete: %v", err) } data, err = f.ClientSet.Extensions().RESTClient().Get().AbsPath("/apis/company.com/v1/foos").DoRaw() if err != nil { framework.Failf("failed to list with no objects: %v", err) } if err := json.Unmarshal(data, &list); err != nil { framework.Failf("failed to decode: %#v", err) }
var file string testPodWithExecHook := func(podWithHook *v1.Pod) { podCheckHook := getExecHookTestPod("pod-check-hook", // Wait until the file is created. []string{"sh", "-c", fmt.Sprintf("while [ ! -e %s ]; do sleep 1; done", file)}, ) By("create the pod with lifecycle hook") podClient.CreateSync(podWithHook) if podWithHook.Spec.Containers[0].Lifecycle.PostStart != nil { By("create the hook check pod") podClient.Create(podCheckHook) By("wait for the hook check pod to success") podClient.WaitForSuccess(podCheckHook.Name, postStartWaitTimeout) } By("delete the pod with lifecycle hook") podClient.DeleteSync(podWithHook.Name, v1.NewDeleteOptions(15), podWaitTimeout) if podWithHook.Spec.Containers[0].Lifecycle.PreStop != nil { By("create the hook check pod") podClient.Create(podCheckHook) By("wait for the prestop check pod to success") podClient.WaitForSuccess(podCheckHook.Name, preStopWaitTimeout) } } BeforeEach(func() { file = "/tmp/test-" + string(uuid.NewUUID()) }) AfterEach(func() { By("cleanup the temporary file created in the test.") cleanupPod := getExecHookTestPod("pod-clean-up", []string{"rm", file})
if initialPetPodUID == "" { return false, nil } return true, nil } framework.Logf("Observed stateful pod in namespace: %v, name: %v, uid: %v, status phase: %v. Waiting for statefulset controller to delete.", pod.Namespace, pod.Name, pod.UID, pod.Status.Phase) initialPetPodUID = pod.UID return false, nil }) if err != nil { framework.Failf("Pod %v expected to be re-created at least once", petPodName) } By("removing pod with conflicting port in namespace " + f.Namespace.Name) err = f.ClientSet.Core().Pods(f.Namespace.Name).Delete(pod.Name, v1.NewDeleteOptions(0)) framework.ExpectNoError(err) By("waiting when stateful pod " + petPodName + " will be recreated in namespace " + f.Namespace.Name + " and will be in running state") // we may catch delete event, thats why we are waiting for running phase like this, and not with watch.Until Eventually(func() error { petPod, err := f.ClientSet.Core().Pods(f.Namespace.Name).Get(petPodName, metav1.GetOptions{}) if err != nil { return err } if petPod.Status.Phase != v1.PodRunning { return fmt.Errorf("Pod %v is not in running phase: %v", petPod.Name, petPod.Status.Phase) } else if petPod.UID == initialPetPodUID { return fmt.Errorf("Pod %v wasn't recreated: %v == %v", petPod.Name, petPod.UID, initialPetPodUID) } return nil
}, 2*time.Minute, time.Second*4).Should(BeNil()) By("check the mirror pod container image is updated") pod, err = f.ClientSet.Core().Pods(ns).Get(mirrorPodName, metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) Expect(len(pod.Spec.Containers)).Should(Equal(1)) Expect(pod.Spec.Containers[0].Image).Should(Equal(image)) }) It("should be recreated when mirror pod gracefully deleted [Conformance]", func() { By("get mirror pod uid") pod, err := f.ClientSet.Core().Pods(ns).Get(mirrorPodName, metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) uid := pod.UID By("delete the mirror pod with grace period 30s") err = f.ClientSet.Core().Pods(ns).Delete(mirrorPodName, v1.NewDeleteOptions(30)) Expect(err).ShouldNot(HaveOccurred()) By("wait for the mirror pod to be recreated") Eventually(func() error { return checkMirrorPodRecreatedAndRunnig(f.ClientSet, mirrorPodName, ns, uid) }, 2*time.Minute, time.Second*4).Should(BeNil()) }) It("should be recreated when mirror pod forcibly deleted [Conformance]", func() { By("get mirror pod uid") pod, err := f.ClientSet.Core().Pods(ns).Get(mirrorPodName, metav1.GetOptions{}) Expect(err).ShouldNot(HaveOccurred()) uid := pod.UID By("delete the mirror pod with grace period 0s") err = f.ClientSet.Core().Pods(ns).Delete(mirrorPodName, v1.NewDeleteOptions(0))
func DoTestUnschedulableNodes(t *testing.T, cs clientset.Interface, ns *v1.Namespace, nodeStore cache.Store) { // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (Nodes). defer cs.Core().Nodes().DeleteCollection(nil, v1.ListOptions{}) goodCondition := v1.NodeCondition{ Type: v1.NodeReady, Status: v1.ConditionTrue, Reason: fmt.Sprintf("schedulable condition"), LastHeartbeatTime: metav1.Time{time.Now()}, } badCondition := v1.NodeCondition{ Type: v1.NodeReady, Status: v1.ConditionUnknown, Reason: fmt.Sprintf("unschedulable condition"), LastHeartbeatTime: metav1.Time{time.Now()}, } // Create a new schedulable node, since we're first going to apply // the unschedulable condition and verify that pods aren't scheduled. node := &v1.Node{ ObjectMeta: v1.ObjectMeta{Name: "node-scheduling-test-node"}, Spec: v1.NodeSpec{Unschedulable: false}, Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []v1.NodeCondition{goodCondition}, }, } nodeKey, err := cache.MetaNamespaceKeyFunc(node) if err != nil { t.Fatalf("Couldn't retrieve key for node %v", node.Name) } // The test does the following for each nodeStateManager in this list: // 1. Create a new node // 2. Apply the makeUnSchedulable function // 3. Create a new pod // 4. Check that the pod doesn't get assigned to the node // 5. Apply the schedulable function // 6. Check that the pod *does* get assigned to the node // 7. Delete the pod and node. nodeModifications := []nodeStateManager{ // Test node.Spec.Unschedulable=true/false { makeUnSchedulable: func(t *testing.T, n *v1.Node, s cache.Store, c clientset.Interface) { n.Spec.Unschedulable = true if _, err := c.Core().Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=true: %v", err) } err = waitForReflection(t, s, nodeKey, func(node interface{}) bool { // An unschedulable node should still be present in the store // Nodes that are unschedulable or that are not ready or // have their disk full (Node.Spec.Conditions) are exluded // based on NodeConditionPredicate, a separate check return node != nil && node.(*v1.Node).Spec.Unschedulable == true }) if err != nil { t.Fatalf("Failed to observe reflected update for setting unschedulable=true: %v", err) } }, makeSchedulable: func(t *testing.T, n *v1.Node, s cache.Store, c clientset.Interface) { n.Spec.Unschedulable = false if _, err := c.Core().Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=false: %v", err) } err = waitForReflection(t, s, nodeKey, func(node interface{}) bool { return node != nil && node.(*v1.Node).Spec.Unschedulable == false }) if err != nil { t.Fatalf("Failed to observe reflected update for setting unschedulable=false: %v", err) } }, }, // Test node.Status.Conditions=ConditionTrue/Unknown { makeUnSchedulable: func(t *testing.T, n *v1.Node, s cache.Store, c clientset.Interface) { n.Status = v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []v1.NodeCondition{badCondition}, } if _, err = c.Core().Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with bad status condition: %v", err) } err = waitForReflection(t, s, nodeKey, func(node interface{}) bool { return node != nil && node.(*v1.Node).Status.Conditions[0].Status == v1.ConditionUnknown }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, makeSchedulable: func(t *testing.T, n *v1.Node, s cache.Store, c clientset.Interface) { n.Status = v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []v1.NodeCondition{goodCondition}, } if _, err = c.Core().Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with healthy status condition: %v", err) } err = waitForReflection(t, s, nodeKey, func(node interface{}) bool { return node != nil && node.(*v1.Node).Status.Conditions[0].Status == v1.ConditionTrue }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, }, } for i, mod := range nodeModifications { unSchedNode, err := cs.Core().Nodes().Create(node) if err != nil { t.Fatalf("Failed to create node: %v", err) } // Apply the unschedulable modification to the node, and wait for the reflection mod.makeUnSchedulable(t, unSchedNode, nodeStore, cs) // Create the new pod, note that this needs to happen post unschedulable // modification or we have a race in the test. pod := &v1.Pod{ ObjectMeta: v1.ObjectMeta{Name: "node-scheduling-test-pod"}, Spec: v1.PodSpec{ Containers: []v1.Container{{Name: "container", Image: e2e.GetPauseImageName(cs)}}, }, } myPod, err := cs.Core().Pods(ns.Name).Create(pod) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // There are no schedulable nodes - the pod shouldn't be scheduled. err = wait.Poll(time.Second, wait.ForeverTestTimeout, podScheduled(cs, myPod.Namespace, myPod.Name)) if err == nil { t.Errorf("Pod scheduled successfully on unschedulable nodes") } if err != wait.ErrWaitTimeout { t.Errorf("Test %d: failed while trying to confirm the pod does not get scheduled on the node: %v", i, err) } else { t.Logf("Test %d: Pod did not get scheduled on an unschedulable node", i) } // Apply the schedulable modification to the node, and wait for the reflection schedNode, err := cs.Core().Nodes().Get(unSchedNode.Name) if err != nil { t.Fatalf("Failed to get node: %v", err) } mod.makeSchedulable(t, schedNode, nodeStore, cs) // Wait until the pod is scheduled. err = wait.Poll(time.Second, wait.ForeverTestTimeout, podScheduled(cs, myPod.Namespace, myPod.Name)) if err != nil { t.Errorf("Test %d: failed to schedule a pod: %v", i, err) } else { t.Logf("Test %d: Pod got scheduled on a schedulable node", i) } err = cs.Core().Pods(ns.Name).Delete(myPod.Name, v1.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } err = cs.Core().Nodes().Delete(schedNode.Name, nil) if err != nil { t.Errorf("Failed to delete node: %v", err) } } }
framework.Failf("Failed to observe pod creation: %v", event) } case <-time.After(framework.PodStartTimeout): Fail("Timeout while waiting for pod creation") } // We need to wait for the pod to be running, otherwise the deletion // may be carried out immediately rather than gracefully. framework.ExpectNoError(f.WaitForPodRunning(pod.Name)) // save the running pod pod, err = podClient.Get(pod.Name, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred(), "failed to GET scheduled pod") framework.Logf("running pod: %#v", pod) By("deleting the pod gracefully") err = podClient.Delete(pod.Name, v1.NewDeleteOptions(30)) Expect(err).NotTo(HaveOccurred(), "failed to delete pod") By("verifying the kubelet observed the termination notice") Expect(wait.Poll(time.Second*5, time.Second*30, func() (bool, error) { podList, err := framework.GetKubeletPods(f.ClientSet, pod.Spec.NodeName) if err != nil { framework.Logf("Unable to retrieve kubelet pods for node %v: %v", pod.Spec.NodeName, err) return false, nil } for _, kubeletPod := range podList.Items { if pod.Name != kubeletPod.Name { continue } if kubeletPod.ObjectMeta.DeletionTimestamp == nil { framework.Logf("deletion has not yet been observed")
By(fmt.Sprintf("Make sure node condition %q is stable", condition)) Consistently(func() error { return verifyCondition(c.Core().Nodes(), node.Name, condition, test.conditionType, test.conditionReason, test.conditionMessage) }, pollConsistent, pollInterval).Should(Succeed()) } }) AfterEach(func() { if CurrentGinkgoTestDescription().Failed && framework.TestContext.DumpLogsOnFailure { By("Get node problem detector log") log, err := framework.GetPodLogs(c, ns, name, name) Expect(err).ShouldNot(HaveOccurred()) framework.Logf("Node Problem Detector logs:\n %s", log) } By("Delete the node problem detector") c.Core().Pods(ns).Delete(name, v1.NewDeleteOptions(0)) By("Wait for the node problem detector to disappear") Expect(framework.WaitForPodToDisappear(c, ns, name, labels.Everything(), pollInterval, pollTimeout)).To(Succeed()) By("Delete the config map") c.Core().ConfigMaps(ns).Delete(configName, nil) By("Clean up the events") Expect(c.Core().Events(eventNamespace).DeleteCollection(v1.NewDeleteOptions(0), eventListOptions)).To(Succeed()) By("Clean up the node condition") patch := []byte(fmt.Sprintf(`{"status":{"conditions":[{"$patch":"delete","type":"%s"}]}}`, condition)) c.Core().RESTClient().Patch(types.StrategicMergePatchType).Resource("nodes").Name(node.Name).SubResource("status").Body(patch).Do() By("Clean up the temporary directory") framework.IssueSSHCommand(fmt.Sprintf("rm -r %s", tmpDir), framework.TestContext.Provider, node) }) }) })
func TestMultiScheduler(t *testing.T) { _, s := framework.RunAMaster(nil) // TODO: Uncomment when fix #19254 // This seems to be a different issue - it still doesn't work. // defer s.Close() ns := framework.CreateTestingNamespace("multi-scheduler", s, t) defer framework.DeleteTestingNamespace(ns, s, t) /* This integration tests the multi-scheduler feature in the following way: 1. create a default scheduler 2. create a node 3. create 3 pods: testPodNoAnnotation, testPodWithAnnotationFitsDefault and testPodWithAnnotationFitsFoo - note: the first two should be picked and scheduled by default scheduler while the last one should be picked by scheduler of name "foo-scheduler" which does not exist yet. 4. **check point-1**: - testPodNoAnnotation, testPodWithAnnotationFitsDefault should be scheduled - testPodWithAnnotationFitsFoo should NOT be scheduled 5. create a scheduler with name "foo-scheduler" 6. **check point-2**: - testPodWithAnnotationFitsFoo should be scheduled 7. stop default scheduler 8. create 2 pods: testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 - note: these two pods belong to default scheduler which no longer exists 9. **check point-3**: - testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 shoule NOT be scheduled */ // 1. create and start default-scheduler clientSet := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}}) // NOTE: This test cannot run in parallel, because it is creating and deleting // non-namespaced objects (Nodes). defer clientSet.Core().Nodes().DeleteCollection(nil, v1.ListOptions{}) schedulerConfigFactory := factory.NewConfigFactory(clientSet, v1.DefaultSchedulerName, v1.DefaultHardPodAffinitySymmetricWeight, v1.DefaultFailureDomains) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { t.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(v1.EventSource{Component: v1.DefaultSchedulerName}) eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: clientSet.Core().Events(ns.Name)}) scheduler.New(schedulerConfig).Run() // default-scheduler will be stopped later // 2. create a node node := &v1.Node{ ObjectMeta: v1.ObjectMeta{Name: "node-multi-scheduler-test-node"}, Spec: v1.NodeSpec{Unschedulable: false}, Status: v1.NodeStatus{ Capacity: v1.ResourceList{ v1.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, }, } clientSet.Core().Nodes().Create(node) // 3. create 3 pods for testing podWithNoAnnotation := createPod(clientSet, "pod-with-no-annotation", nil) testPodNoAnnotation, err := clientSet.Core().Pods(ns.Name).Create(podWithNoAnnotation) if err != nil { t.Fatalf("Failed to create pod: %v", err) } schedulerAnnotationFitsDefault := map[string]string{"scheduler.alpha.kubernetes.io/name": "default-scheduler"} podWithAnnotationFitsDefault := createPod(clientSet, "pod-with-annotation-fits-default", schedulerAnnotationFitsDefault) testPodWithAnnotationFitsDefault, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsDefault) if err != nil { t.Fatalf("Failed to create pod: %v", err) } schedulerAnnotationFitsFoo := map[string]string{"scheduler.alpha.kubernetes.io/name": "foo-scheduler"} podWithAnnotationFitsFoo := createPod(clientSet, "pod-with-annotation-fits-foo", schedulerAnnotationFitsFoo) testPodWithAnnotationFitsFoo, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsFoo) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // 4. **check point-1**: // - testPodNoAnnotation, testPodWithAnnotationFitsDefault should be scheduled // - testPodWithAnnotationFitsFoo should NOT be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodNoAnnotation.Namespace, testPodNoAnnotation.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled: %v", testPodNoAnnotation.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodNoAnnotation.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsDefault.Namespace, testPodWithAnnotationFitsDefault.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled: %v", testPodWithAnnotationFitsDefault.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsDefault.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsFoo.Namespace, testPodWithAnnotationFitsFoo.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodWithAnnotationFitsFoo.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod not scheduled", testPodWithAnnotationFitsFoo.Name) } // 5. create and start a scheduler with name "foo-scheduler" clientSet2 := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(v1.GroupName).GroupVersion}}) schedulerConfigFactory2 := factory.NewConfigFactory(clientSet2, "foo-scheduler", v1.DefaultHardPodAffinitySymmetricWeight, v1.DefaultFailureDomains) schedulerConfig2, err := schedulerConfigFactory2.Create() if err != nil { t.Errorf("Couldn't create scheduler config: %v", err) } eventBroadcaster2 := record.NewBroadcaster() schedulerConfig2.Recorder = eventBroadcaster2.NewRecorder(v1.EventSource{Component: "foo-scheduler"}) eventBroadcaster2.StartRecordingToSink(&v1core.EventSinkImpl{Interface: clientSet2.Core().Events(ns.Name)}) scheduler.New(schedulerConfig2).Run() defer close(schedulerConfig2.StopEverything) // 6. **check point-2**: // - testPodWithAnnotationFitsFoo should be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsFoo.Namespace, testPodWithAnnotationFitsFoo.Name)) if err != nil { t.Errorf("Test MultiScheduler: %s Pod not scheduled, %v", testPodWithAnnotationFitsFoo.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsFoo.Name) } // 7. delete the pods that were scheduled by the default scheduler, and stop the default scheduler err = clientSet.Core().Pods(ns.Name).Delete(testPodNoAnnotation.Name, v1.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } err = clientSet.Core().Pods(ns.Name).Delete(testPodWithAnnotationFitsDefault.Name, v1.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } // The rest of this test assumes that closing StopEverything will cause the // scheduler thread to stop immediately. It won't, and in fact it will often // schedule 1 more pod before finally exiting. Comment out until we fix that. // // See https://github.com/kubernetes/kubernetes/issues/23715 for more details. /* close(schedulerConfig.StopEverything) // 8. create 2 pods: testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 // - note: these two pods belong to default scheduler which no longer exists podWithNoAnnotation2 := createPod("pod-with-no-annotation2", nil) podWithAnnotationFitsDefault2 := createPod("pod-with-annotation-fits-default2", schedulerAnnotationFitsDefault) testPodNoAnnotation2, err := clientSet.Core().Pods(ns.Name).Create(podWithNoAnnotation2) if err != nil { t.Fatalf("Failed to create pod: %v", err) } testPodWithAnnotationFitsDefault2, err := clientSet.Core().Pods(ns.Name).Create(podWithAnnotationFitsDefault2) if err != nil { t.Fatalf("Failed to create pod: %v", err) } // 9. **check point-3**: // - testPodNoAnnotation2 and testPodWithAnnotationFitsDefault2 shoule NOT be scheduled err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodNoAnnotation2.Namespace, testPodNoAnnotation2.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodNoAnnotation2.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod not scheduled", testPodNoAnnotation2.Name) } err = wait.Poll(time.Second, time.Second*5, podScheduled(clientSet, testPodWithAnnotationFitsDefault2.Namespace, testPodWithAnnotationFitsDefault2.Name)) if err == nil { t.Errorf("Test MultiScheduler: %s Pod got scheduled, %v", testPodWithAnnotationFitsDefault2.Name, err) } else { t.Logf("Test MultiScheduler: %s Pod scheduled", testPodWithAnnotationFitsDefault2.Name) } */ }
func (cc *ConformanceContainer) Delete() error { return cc.PodClient.Delete(cc.podName, v1.NewDeleteOptions(0)) }