func (t *Tester) testDeleteGracefulImmediate(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, "foo4") if err := setFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } if _, err := getFn(ctx, foo); err != nil { t.Fatalf("did not gracefully delete resource", err) } // second delete is immediate, resource is deleted out, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(0)) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if !errors.IsNotFound(err) { t.Errorf("unexpected error, object should be deleted immediately: %v", err) } objectMeta = t.getObjectMetaOrFail(out) if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 { t.Errorf("unexpected deleted meta: %#v", objectMeta) } }
func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, "foo3") if err := setFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } if _, err := getFn(ctx, foo); err != nil { t.Fatalf("did not gracefully delete resource", err) } // second delete duration is ignored _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if err != nil { t.Errorf("unexpected error, object should exist: %v", err) } objectMeta = t.getObjectMetaOrFail(object) if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace { t.Errorf("unexpected deleted meta: %#v", objectMeta) } }
func ReapResult(r *resource.Result, f *cmdutil.Factory, resp *restful.Response, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int) error { var obj runtime.Object found := 0 if ignoreNotFound { r = r.IgnoreErrors(errors.IsNotFound) } err := r.Visit(func(info *resource.Info) error { found++ reaper, err := f.Reaper(info.Mapping) if err != nil { // If there is no reaper for this resources and the user didn't explicitly ask for stop. if kubectl.IsNoSuchReaperError(err) && isDefaultDelete { return deleteResource(info, resp) } return cmdutil.AddSourceToErr("reaping", info.Source, err) } var options *api.DeleteOptions if gracePeriod >= 0 { options = api.NewDeleteOptions(int64(gracePeriod)) } if _, err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil { return cmdutil.AddSourceToErr("stopping", info.Source, err) } message := fmt.Sprintf("delete %s/%s success", info.Mapping.Resource, info.Name) resp.WriteAsJson(ApiResult{message, info.Object, true}) return nil }) if err != nil { return err } if found == 0 { resp.WriteAsJson(ApiResult{"no resources found", obj, true}) } return nil }
func (t *Tester) testDeleteNoGraceful(obj runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, "foo1") if err := setFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) obj, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10)) if err != nil { t.Errorf("unexpected error: %v", err) } if !t.returnDeletedObject { if status, ok := obj.(*unversioned.Status); !ok { t.Errorf("expected status of delete, got %v", status) } else if status.Status != unversioned.StatusSuccess { t.Errorf("expected success, got: %v", status.Status) } } _, err = getFn(ctx, foo) if err == nil || !isNotFoundFn(err) { t.Errorf("unexpected error: %v", err) } }
func validateDNSResults(f *Framework, pod *api.Pod, fileNames []string) { By("submitting the pod to kubernetes") podClient := f.Client.Pods(f.Namespace.Name) defer func() { By("deleting the pod") defer GinkgoRecover() podClient.Delete(pod.Name, api.NewDeleteOptions(0)) }() if _, err := podClient.Create(pod); err != nil { Failf("Failed to create %s pod: %v", pod.Name, err) } expectNoError(f.WaitForPodRunning(pod.Name)) By("retrieving the pod") pod, err := podClient.Get(pod.Name) if err != nil { Failf("Failed to get pod %s: %v", pod.Name, err) } // Try to find results for each expected name. By("looking for the results for each expected name from probiers") assertFilesExist(fileNames, "results", pod, f.Client) // TODO: probe from the host, too. Logf("DNS probes using %s succeeded\n", pod.Name) }
func checkExistingRCRecovers(f Framework) { By("assert that the pre-existing replication controller recovers") podClient := f.Client.Pods(f.Namespace.Name) rcSelector := labels.Set{"name": "baz"}.AsSelector() By("deleting pods from existing replication controller") expectNoError(wait.Poll(time.Millisecond*500, time.Second*60, func() (bool, error) { pods, err := podClient.List(rcSelector, fields.Everything()) if err != nil { 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, api.NewDeleteOptions(0)) Expect(err).NotTo(HaveOccurred()) } Logf("apiserver has recovered") return true, nil })) By("waiting for replication controller to recover") expectNoError(wait.Poll(time.Millisecond*500, time.Second*60, func() (bool, error) { pods, err := podClient.List(rcSelector, fields.Everything()) Expect(err).NotTo(HaveOccurred()) for _, pod := range pods.Items { if pod.DeletionTimestamp == nil && api.IsPodReady(&pod) { return true, nil } } return false, nil })) }
func New(kubeClient client.Interface, resyncPeriod controller.ResyncPeriodFunc, threshold int) *GCController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(kubeClient.Events("")) gcc := &GCController{ kubeClient: kubeClient, threshold: threshold, deletePod: func(namespace, name string) error { return kubeClient.Pods(namespace).Delete(name, api.NewDeleteOptions(0)) }, } terminatedSelector := compileTerminatedPodSelector() gcc.podStore.Store, gcc.podStoreSyncer = framework.NewInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return gcc.kubeClient.Pods(api.NamespaceAll).List(labels.Everything(), terminatedSelector) }, WatchFunc: func(rv string) (watch.Interface, error) { return gcc.kubeClient.Pods(api.NamespaceAll).Watch(labels.Everything(), terminatedSelector, rv) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{}, ) return gcc }
// testHostIP tests that a pod gets a host IP func testHostIP(c *client.Client, ns string, pod *api.Pod) { podClient := c.Pods(ns) By("creating pod") defer podClient.Delete(pod.Name, api.NewDeleteOptions(0)) if _, err := podClient.Create(pod); err != nil { Failf("Failed to create pod: %v", err) } By("ensuring that pod is running and has a hostIP") // Wait for the pods to enter the running state. Waiting loops until the pods // are running so non-running pods cause a timeout for this test. err := waitForPodRunningInNamespace(c, pod.Name, ns) Expect(err).NotTo(HaveOccurred()) // Try to make sure we get a hostIP for each pod. hostIPTimeout := 2 * time.Minute t := time.Now() for { p, err := podClient.Get(pod.Name) Expect(err).NotTo(HaveOccurred()) if p.Status.HostIP != "" { Logf("Pod %s has hostIP: %s", p.Name, p.Status.HostIP) break } if time.Since(t) >= hostIPTimeout { Failf("Gave up waiting for hostIP of pod %s after %v seconds", p.Name, time.Since(t).Seconds()) } Logf("Retrying to get the hostIP of pod %s", p.Name) time.Sleep(5 * time.Second) } }
func deletePods(kubeClient client.Interface, ns string, before unversioned.Time) (int64, error) { items, err := kubeClient.Pods(ns).List(labels.Everything(), fields.Everything()) if err != nil { return 0, err } expired := unversioned.Now().After(before.Time) var deleteOptions *api.DeleteOptions if expired { deleteOptions = api.NewDeleteOptions(0) } estimate := int64(0) for i := range items.Items { if items.Items[i].Spec.TerminationGracePeriodSeconds != nil { grace := *items.Items[i].Spec.TerminationGracePeriodSeconds if grace > estimate { estimate = grace } } err := kubeClient.Pods(ns).Delete(items.Items[i].Name, deleteOptions) if err != nil && !errors.IsNotFound(err) { return 0, err } } if expired { estimate = 0 } return estimate, nil }
func runSchedulerNoPhantomPodsTest(client *client.Client) { pod := &api.Pod{ Spec: api.PodSpec{ Containers: []api.Container{ { Name: "c1", Image: "kubernetes/pause", Ports: []api.ContainerPort{ {ContainerPort: 1234, HostPort: 9999}, }, ImagePullPolicy: api.PullIfNotPresent, }, }, }, } // Assuming we only have two kublets, the third pod here won't schedule // if the scheduler doesn't correctly handle the delete for the second // pod. pod.ObjectMeta.Name = "phantom.foo" foo, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*30, podRunning(client, foo.Namespace, foo.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } pod.ObjectMeta.Name = "phantom.bar" bar, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*30, podRunning(client, bar.Namespace, bar.Name)); err != nil { glog.Fatalf("FAILED: pod never started running %v", err) } // Delete a pod to free up room. glog.Infof("Deleting pod %v", bar.Name) err = client.Pods(api.NamespaceDefault).Delete(bar.Name, api.NewDeleteOptions(0)) if err != nil { glog.Fatalf("FAILED: couldn't delete pod %q: %v", bar.Name, err) } pod.ObjectMeta.Name = "phantom.baz" baz, err := client.Pods(api.NamespaceDefault).Create(pod) if err != nil { glog.Fatalf("Failed to create pod: %v, %v", pod, err) } if err := wait.Poll(time.Second, time.Second*60, podRunning(client, baz.Namespace, baz.Name)); err != nil { if pod, perr := client.Pods(api.NamespaceDefault).Get("phantom.bar"); perr == nil { glog.Fatalf("FAILED: 'phantom.bar' was never deleted: %#v", pod) } else { glog.Fatalf("FAILED: (Scheduler probably didn't process deletion of 'phantom.bar') Pod never started running: %v", err) } } glog.Info("Scheduler doesn't make phantom pods: test passed.") }
func runLivenessTest(c *client.Client, ns string, podDescr *api.Pod, expectNumRestarts int) { By(fmt.Sprintf("Creating pod %s in namespace %s", podDescr.Name, ns)) _, err := c.Pods(ns).Create(podDescr) expectNoError(err, fmt.Sprintf("creating pod %s", podDescr.Name)) // At the end of the test, clean up by removing the pod. defer func() { By("deleting the pod") c.Pods(ns).Delete(podDescr.Name, api.NewDeleteOptions(0)) }() // 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.) expectNoError(waitForPodNotPending(c, ns, podDescr.Name), fmt.Sprintf("starting pod %s in namespace %s", podDescr.Name, ns)) By(fmt.Sprintf("Started pod %s in namespace %s", podDescr.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 := c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s in namespace %s", podDescr.Name, ns)) initialRestartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount By(fmt.Sprintf("Initial restart count of pod %s is %d", podDescr.Name, initialRestartCount)) // Wait for the restart state to be as desired. deadline := time.Now().Add(2 * time.Minute) lastRestartCount := initialRestartCount observedRestarts := 0 for start := time.Now(); time.Now().Before(deadline); time.Sleep(2 * time.Second) { pod, err = c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s", podDescr.Name)) restartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount if restartCount != lastRestartCount { By(fmt.Sprintf("Restart count of pod %s/%s is now %d (%v elapsed)", ns, podDescr.Name, restartCount, time.Since(start))) if restartCount < lastRestartCount { Failf("Restart count should increment monotonically: restart cont of pod %s/%s changed from %d to %d", ns, podDescr.Name, lastRestartCount, restartCount) } } observedRestarts = restartCount - initialRestartCount if expectNumRestarts > 0 && 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 && observedRestarts < expectNumRestarts) { Failf("pod %s/%s - expected number of restarts: %t, found restarts: %t", ns, podDescr.Name, expectNumRestarts, observedRestarts) } }
func cleanupPods(c *client.Client, ns string) { By("Removing all pods in namespace " + ns) pods, err := c.Pods(ns).List(labels.Everything(), fields.Everything()) expectNoError(err) opt := api.NewDeleteOptions(0) for _, p := range pods.Items { expectNoError(c.Pods(ns).Delete(p.ObjectMeta.Name, opt)) } }
// syncBatch syncs pods statuses with the apiserver. func (m *manager) syncBatch() error { syncRequest := <-m.podStatusChannel pod := syncRequest.pod status := syncRequest.status var err error statusPod := &api.Pod{ ObjectMeta: pod.ObjectMeta, } // TODO: make me easier to express from client code statusPod, err = m.kubeClient.Pods(statusPod.Namespace).Get(statusPod.Name) if errors.IsNotFound(err) { glog.V(3).Infof("Pod %q was deleted on the server", pod.Name) return nil } if err == nil { if len(pod.UID) > 0 && statusPod.UID != pod.UID { glog.V(3).Infof("Pod %q was deleted and then recreated, skipping status update", kubeletUtil.FormatPodName(pod)) return nil } statusPod.Status = status // TODO: handle conflict as a retry, make that easier too. statusPod, err = m.kubeClient.Pods(pod.Namespace).UpdateStatus(statusPod) if err == nil { glog.V(3).Infof("Status for pod %q updated successfully", kubeletUtil.FormatPodName(pod)) if pod.DeletionTimestamp == nil { return nil } if !notRunning(pod.Status.ContainerStatuses) { glog.V(3).Infof("Pod %q is terminated, but some pods are still running", pod.Name) return nil } if err := m.kubeClient.Pods(statusPod.Namespace).Delete(statusPod.Name, api.NewDeleteOptions(0)); err == nil { glog.V(3).Infof("Pod %q fully terminated and removed from etcd", statusPod.Name) m.DeletePodStatus(pod.UID) return nil } } } // We failed to update status. In order to make sure we retry next time // we delete cached value. This may result in an additional update, but // this is ok. // Doing this synchronously will lead to a deadlock if the podStatusChannel // is full, and the pod worker holding the lock is waiting on this method // to clear the channel. Even if this delete never runs subsequent container // changes on the node should trigger updates. go m.DeletePodStatus(pod.UID) return fmt.Errorf("error updating status for pod %q: %v", kubeletUtil.FormatPodName(pod), err) }
// terminatePods will ensure all pods on the given node that are in terminating state are eventually // cleaned up. Returns true if the node has no pods in terminating state, a duration that indicates how // long before we should check again (the next deadline for a pod to complete), or an error. func (nc *NodeController) terminatePods(nodeName string, since time.Time) (bool, time.Duration, error) { // the time before we should try again nextAttempt := time.Duration(0) // have we deleted all pods complete := true pods, err := nc.kubeClient.Pods(api.NamespaceAll).List(labels.Everything(), fields.OneTermEqualSelector(client.PodHost, nodeName)) if err != nil { return false, nextAttempt, err } now := time.Now() elapsed := now.Sub(since) for _, pod := range pods.Items { // Defensive check, also needed for tests. if pod.Spec.NodeName != nodeName { continue } // only clean terminated pods if pod.DeletionGracePeriodSeconds == nil { continue } // the user's requested grace period grace := time.Duration(*pod.DeletionGracePeriodSeconds) * time.Second if grace > nc.maximumGracePeriod { grace = nc.maximumGracePeriod } // the time remaining before the pod should have been deleted remaining := grace - elapsed if remaining < 0 { remaining = 0 glog.V(2).Infof("Removing pod %v after %s grace period", pod.Name, grace) nc.recordNodeEvent(nodeName, "TerminatingEvictedPod", fmt.Sprintf("Pod %s has exceeded the grace period for deletion after being evicted from Node %q and is being force killed", pod.Name, nodeName)) if err := nc.kubeClient.Pods(pod.Namespace).Delete(pod.Name, api.NewDeleteOptions(0)); err != nil { glog.Errorf("Error completing deletion of pod %s: %v", pod.Name, err) complete = false } } else { glog.V(2).Infof("Pod %v still terminating, requested grace period %s, %s remaining", pod.Name, grace, remaining) complete = false } if nextAttempt < remaining { nextAttempt = remaining } } return complete, nextAttempt, nil }
// Deletes a mirror pod. 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(4).Infof("Deleting a mirror pod %q", podFullName) if err := mc.apiserverClient.Pods(namespace).Delete(name, api.NewDeleteOptions(0)); err != nil { glog.Errorf("Failed deleting a mirror pod %q: %v", podFullName, err) } return nil }
func (t *Tester) TestDeleteNoGraceful(createFn func() runtime.Object, wasGracefulFn func() bool) { existing := createFn() objectMeta, err := api.ObjectMetaFor(existing) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) } ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10)) if err != nil { t.Errorf("unexpected error: %v", err) } if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) { t.Errorf("unexpected error, object should not exist: %v", err) } if wasGracefulFn() { t.Errorf("resource should not support graceful delete") } }
func ReapResult(r *resource.Result, f *cmdutil.Factory, out io.Writer, isDefaultDelete, ignoreNotFound bool, timeout time.Duration, gracePeriod int, shortOutput bool, mapper meta.RESTMapper) error { found := 0 if ignoreNotFound { r = r.IgnoreErrors(errors.IsNotFound) } err := r.Visit(func(info *resource.Info, err error) error { if err != nil { return err } found++ reaper, err := f.Reaper(info.Mapping) if err != nil { // If there is no reaper for this resources and the user didn't explicitly ask for stop. if kubectl.IsNoSuchReaperError(err) && isDefaultDelete { return deleteResource(info, out, shortOutput, mapper) } return cmdutil.AddSourceToErr("reaping", info.Source, err) } var options *api.DeleteOptions if gracePeriod >= 0 { options = api.NewDeleteOptions(int64(gracePeriod)) } if _, err := reaper.Stop(info.Namespace, info.Name, timeout, options); err != nil { return cmdutil.AddSourceToErr("stopping", info.Source, err) } cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "deleted") return nil }) if err != nil { return err } if found == 0 { fmt.Fprintf(out, "No resources found\n") } return nil }
// Delete removes the item from etcd. func (e *Etcd) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) { key, err := e.KeyFunc(ctx, name) if err != nil { return nil, err } obj := e.NewFunc() trace := util.NewTrace("Delete " + reflect.TypeOf(obj).String()) defer trace.LogIfLong(time.Second) trace.Step("About to read object") if err := e.Storage.Get(key, obj, false); err != nil { return nil, etcderr.InterpretDeleteError(err, e.EndpointName, name) } // support older consumers of delete by treating "nil" as delete immediately if options == nil { options = api.NewDeleteOptions(0) } graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, obj, options) if err != nil { return nil, err } if pendingGraceful { return e.finalizeDelete(obj, false) } if graceful { trace.Step("Graceful deletion") out := e.NewFunc() lastGraceful := int64(0) err := e.Storage.GuaranteedUpdate( key, out, false, storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) { graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, existing, options) if err != nil { return nil, err } if pendingGraceful { return nil, errAlreadyDeleting } if !graceful { return nil, errDeleteNow } lastGraceful = *options.GracePeriodSeconds return existing, nil }), ) switch err { case nil: if lastGraceful > 0 { return out, nil } // fall through and delete immediately case errDeleteNow: // we've updated the object to have a zero grace period, or it's already at 0, so // we should fall through and truly delete the object. case errAlreadyDeleting: return e.finalizeDelete(obj, true) default: return nil, etcderr.InterpretUpdateError(err, e.EndpointName, name) } } // delete immediately, or no graceful deletion supported out := e.NewFunc() trace.Step("About to delete object") if err := e.Storage.Delete(key, out); err != nil { return nil, etcderr.InterpretDeleteError(err, e.EndpointName, name) } return e.finalizeDelete(out, true) }
It("should schedule a pod w/ a RW PD, remove it, then schedule it on another host", func() { SkipUnlessProviderIs("gce", "gke", "aws") By("creating PD") diskName, err := createPD() 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() { By("cleaning up PD-RW test environment") // Teardown pods, PD. Ignore errors. // Teardown should do nothing unless test failed. podClient.Delete(host0Pod.Name, api.NewDeleteOptions(0)) podClient.Delete(host1Pod.Name, api.NewDeleteOptions(0)) detachPD(host0Name, diskName) detachPD(host1Name, diskName) deletePDWithRetry(diskName) }() By("submitting host0Pod to kubernetes") _, err = podClient.Create(host0Pod) expectNoError(err, fmt.Sprintf("Failed to create host0Pod: %v", err)) expectNoError(framework.WaitForPodRunningSlow(host0Pod.Name)) testFile := "/testpd1/tracker" testFileContents := fmt.Sprintf("%v", math_rand.Int())
func DoTestUnschedulableNodes(t *testing.T, restClient *client.Client, nodeStore cache.Store) { goodCondition := api.NodeCondition{ Type: api.NodeReady, Status: api.ConditionTrue, Reason: fmt.Sprintf("schedulable condition"), LastHeartbeatTime: unversioned.Time{time.Now()}, } badCondition := api.NodeCondition{ Type: api.NodeReady, Status: api.ConditionUnknown, Reason: fmt.Sprintf("unschedulable condition"), LastHeartbeatTime: unversioned.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 := &api.Node{ ObjectMeta: api.ObjectMeta{Name: "node-scheduling-test-node"}, Spec: api.NodeSpec{Unschedulable: false}, Status: api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.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 *api.Node, s cache.Store, c *client.Client) { n.Spec.Unschedulable = true if _, err := c.Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=true: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { // An unschedulable node should get deleted from the store return node == nil }) if err != nil { t.Fatalf("Failed to observe reflected update for setting unschedulable=true: %v", err) } }, makeSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Spec.Unschedulable = false if _, err := c.Nodes().Update(n); err != nil { t.Fatalf("Failed to update node with unschedulable=false: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.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 *api.Node, s cache.Store, c *client.Client) { n.Status = api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.NodeCondition{badCondition}, } if _, err = c.Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with bad status condition: %v", err) } err = waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.Node).Status.Conditions[0].Status == api.ConditionUnknown }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, makeSchedulable: func(t *testing.T, n *api.Node, s cache.Store, c *client.Client) { n.Status = api.NodeStatus{ Capacity: api.ResourceList{ api.ResourcePods: *resource.NewQuantity(32, resource.DecimalSI), }, Conditions: []api.NodeCondition{goodCondition}, } if _, err = c.Nodes().UpdateStatus(n); err != nil { t.Fatalf("Failed to update node with healthy status condition: %v", err) } waitForReflection(s, nodeKey, func(node interface{}) bool { return node != nil && node.(*api.Node).Status.Conditions[0].Status == api.ConditionTrue }) if err != nil { t.Fatalf("Failed to observe reflected update for status condition update: %v", err) } }, }, } for i, mod := range nodeModifications { unSchedNode, err := restClient.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, restClient) // Create the new pod, note that this needs to happen post unschedulable // modification or we have a race in the test. pod := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "node-scheduling-test-pod"}, Spec: api.PodSpec{ Containers: []api.Container{{Name: "container", Image: "kubernetes/pause:go"}}, }, } myPod, err := restClient.Pods(api.NamespaceDefault).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, util.ForeverTestTimeout, podScheduled(restClient, 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 := restClient.Nodes().Get(unSchedNode.Name) if err != nil { t.Fatalf("Failed to get node: %v", err) } mod.makeSchedulable(t, schedNode, nodeStore, restClient) // Wait until the pod is scheduled. err = wait.Poll(time.Second, util.ForeverTestTimeout, podScheduled(restClient, 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 = restClient.Pods(api.NamespaceDefault).Delete(myPod.Name, api.NewDeleteOptions(0)) if err != nil { t.Errorf("Failed to delete pod: %v", err) } err = restClient.Nodes().Delete(schedNode.Name) if err != nil { t.Errorf("Failed to delete node: %v", err) } } }
It("should stop a job", func() { By("Creating a job") job := newTestJob("notTerminate", "foo", api.RestartPolicyNever, parallelism, completions) job, err := createJob(f.Client, f.Namespace.Name, job) Expect(err).NotTo(HaveOccurred()) By("Ensuring active pods == parallelism") err = waitForAllPodsRunning(f.Client, f.Namespace.Name, job.Name, parallelism) Expect(err).NotTo(HaveOccurred()) By("scale job down") reaper, err := kubectl.ReaperFor("Job", f.Client) Expect(err).NotTo(HaveOccurred()) timeout := 1 * time.Minute _, err = reaper.Stop(f.Namespace.Name, job.Name, timeout, api.NewDeleteOptions(0)) Expect(err).NotTo(HaveOccurred()) By("Ensuring job was deleted") _, err = f.Client.Extensions().Jobs(f.Namespace.Name).Get(job.Name) Expect(err).To(HaveOccurred()) Expect(errors.IsNotFound(err)).To(BeTrue()) }) }) // newTestJob returns a job which does one of several testing behaviors. func newTestJob(behavior, name string, rPol api.RestartPolicy, parallelism, completions int) *extensions.Job { job := &extensions.Job{ ObjectMeta: api.ObjectMeta{ Name: name, },
func deleteJob(c *client.Client, ns, name string) error { return c.Extensions().Jobs(ns).Delete(name, api.NewDeleteOptions(0)) }
} // Clean up the goproxyPod cleanup(goproxyPodPath, ns, goproxyPodSelector) } }) It("should support inline execution and attach", func() { nsFlag := fmt.Sprintf("--namespace=%v", ns) By("executing a command with run and attach with stdin") runOutput := newKubectlCommand(nsFlag, "run", "run-test", "--image=busybox", "--restart=Never", "--attach=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'"). withStdinData("abcd1234"). execOrDie() Expect(runOutput).To(ContainSubstring("abcd1234")) Expect(runOutput).To(ContainSubstring("stdin closed")) Expect(c.Pods(ns).Delete("run-test", api.NewDeleteOptions(0))).To(BeNil()) By("executing a command with run and attach without stdin") runOutput = newKubectlCommand(fmt.Sprintf("--namespace=%v", ns), "run", "run-test-2", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--", "sh", "-c", "cat && echo 'stdin closed'"). withStdinData("abcd1234"). execOrDie() Expect(runOutput).ToNot(ContainSubstring("abcd1234")) Expect(runOutput).To(ContainSubstring("stdin closed")) Expect(c.Pods(ns).Delete("run-test-2", api.NewDeleteOptions(0))).To(BeNil()) By("executing a command with run and attach with stdin with open stdin should remain running") runOutput = newKubectlCommand(nsFlag, "run", "run-test-3", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'"). withStdinData("abcd1234\n"). execOrDie() Expect(runOutput).ToNot(ContainSubstring("stdin closed")) if !checkPodsRunningReady(c, ns, []string{"run-test-3"}, time.Minute) {
pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})), fields.Everything()) if err != nil { Failf("Failed to query for pods: %v", err) } Expect(len(pods.Items)).To(Equal(0)) w, err := podClient.Watch( labels.SelectorFromSet(labels.Set(map[string]string{"time": value})), fields.Everything(), pods.ListMeta.ResourceVersion) if err != nil { Failf("Failed to set up watch: %v", err) } By("submitting the pod to kubernetes") // We call defer here in case there is a problem with // the test so we can ensure that we clean up after // ourselves defer podClient.Delete(pod.Name, api.NewDeleteOptions(0)) _, err = podClient.Create(pod) if err != nil { Failf("Failed to create pod: %v", err) } By("verifying the pod is in kubernetes") pods, err = podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})), fields.Everything()) if err != nil { Failf("Failed to query for pods: %v", err) } Expect(len(pods.Items)).To(Equal(1)) By("verifying pod creation was observed") select { case event, _ := <-w.ResultChan():