func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { 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(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } if !wasGracefulFn() { t.Errorf("did not gracefully delete resource") } // 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, err = api.ObjectMetaFor(out) if err != nil { t.Errorf("unexpected error: %v", err) return } if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 { t.Errorf("unexpected deleted meta: %#v", objectMeta) } }
func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, createFn CreateFunc, getFn GetFunc, expectedGrace int64) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(3)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) generation := objectMeta.Generation _, 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: %v", 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, &metav1.GetOptions{}) 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) } if generation >= objectMeta.Generation { t.Error("Generation wasn't bumped when deletion timestamp was set") } }
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) // the second delete shouldn't update the object, so the objectMeta.DeletionGracePeriodSeconds should eqaul to the value set in the first delete. 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 (t *Tester) TestDeleteGracefulWithValue(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { 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(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } if !wasGracefulFn() { t.Errorf("did not gracefully delete resource") } object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if err != nil { t.Errorf("unexpected error, object should exist: %v", err) } objectMeta, err = api.ObjectMetaFor(object) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) } if objectMeta.DeletionTimestamp == nil { t.Errorf("did not set deletion timestamp") } if objectMeta.DeletionGracePeriodSeconds == nil { t.Fatalf("did not set deletion grace period seconds") } if *objectMeta.DeletionGracePeriodSeconds != expectedGrace+2 { t.Errorf("actual grace period does not match expected: %d", *objectMeta.DeletionGracePeriodSeconds) } }
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) 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, 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 }
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 := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: podName, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "federated-service-discovery-container", Image: "gcr.io/google_containers/busybox:1.24", Command: command, }, }, RestartPolicy: api.RestartPolicyOnFailure, }, } _, err := f.Client.Pods(f.Namespace.Name).Create(pod) framework.ExpectNoError(err, "Trying to create pod to run %q", command) defer func() { f.Client.Pods(f.Namespace.Name).Delete(podName, api.NewDeleteOptions(0)) }() if exists { // TODO(mml): Eventually check the IP address is correct, too. Eventually(podExitCodeDetector(f, podName, 0), 3*DNSTTL, time.Second*2). Should(BeNil(), "%q should exit 0, but it never did", command) } else { Consistently(podExitCodeDetector(f, podName, 0), 3*DNSTTL, time.Second*2). ShouldNot(BeNil(), "%q should never exit 0, but it did", command) } }
// Debug creates and runs a debugging pod. func (o *DebugOptions) Debug() error { pod, originalCommand := o.transformPodForDebug(o.Annotations) var commandString string switch { case len(originalCommand) > 0: commandString = strings.Join(originalCommand, " ") default: commandString = "<image entrypoint>" } if o.Print != nil { return o.Print(pod, o.Attach.Out) } glog.V(5).Infof("Creating pod: %#v", pod) fmt.Fprintf(o.Attach.Err, "Debugging with pod/%s, original command: %s\n", pod.Name, commandString) pod, err := o.createPod(pod) if err != nil { return err } // ensure the pod is cleaned up on shutdown o.Attach.InterruptParent = interrupt.New( func(os.Signal) { os.Exit(1) }, func() { fmt.Fprintf(o.Attach.Err, "\nRemoving debug pod ...\n") if err := o.Attach.Client.Pods(pod.Namespace).Delete(pod.Name, kapi.NewDeleteOptions(0)); err != nil { fmt.Fprintf(o.Attach.Err, "error: unable to delete the debug pod %q: %v", pod.Name, err) } }, ) glog.V(5).Infof("Created attach arguments: %#v", o.Attach) return o.Attach.InterruptParent.Run(func() error { w, err := o.Attach.Client.Pods(pod.Namespace).Watch(SingleObject(pod.ObjectMeta)) if err != nil { return err } fmt.Fprintf(o.Attach.Err, "Waiting for pod to start ...\n") switch _, err := Until(o.Timeout, w, PodContainerRunning(o.Attach.ContainerName)); { // switch to logging output case err == ErrPodCompleted, !o.Attach.Stdin: _, err := kcmd.LogsOptions{ Object: pod, Options: &kapi.PodLogOptions{ Container: o.Attach.ContainerName, Follow: true, }, Out: o.Attach.Out, LogsForObject: o.LogsForObject, }.RunLogs() return err case err != nil: return err default: // TODO: attach can race with pod completion, allow attach to switch to logs return o.Attach.Run() } }) }
// hacked from GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/scheduler.go, // with the Modeler stuff removed since we don't use it because we have mesos. func (s *controller) scheduleOne() { pod := s.nextPod() // pods which are pre-scheduled (i.e. NodeName is set) are deleted by the kubelet // in upstream. Not so in Mesos because the kubelet hasn't see that pod yet. Hence, // the scheduler has to take care of this: if pod.Spec.NodeName != "" && pod.DeletionTimestamp != nil { log.V(3).Infof("deleting pre-scheduled, not yet running pod: %s/%s", pod.Namespace, pod.Name) s.client.Core().Pods(pod.Namespace).Delete(pod.Name, api.NewDeleteOptions(0)) return } log.V(3).Infof("Attempting to schedule: %+v", pod) dest, err := s.algorithm.Schedule(pod) if err != nil { log.V(1).Infof("Failed to schedule: %+v", pod) s.recorder.Eventf(pod, api.EventTypeWarning, FailedScheduling, "Error scheduling: %v", err) s.error(pod, err) return } b := &api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name}, Target: api.ObjectReference{ Kind: "Node", Name: dest, }, } if err := s.binder.Bind(b); err != nil { log.V(1).Infof("Failed to bind pod: %+v", err) s.recorder.Eventf(pod, api.EventTypeWarning, FailedScheduling, "Binding rejected: %v", err) s.error(pod, err) return } s.recorder.Eventf(pod, api.EventTypeNormal, Scheduled, "Successfully assigned %v to %v", pod.Name, dest) }
func NewPodGC(kubeClient clientset.Interface, podInformer cache.SharedIndexInformer, terminatedPodThreshold int) *PodGCController { if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } gcc := &PodGCController{ kubeClient: kubeClient, terminatedPodThreshold: terminatedPodThreshold, deletePod: func(namespace, name string) error { return kubeClient.Core().Pods(namespace).Delete(name, api.NewDeleteOptions(0)) }, } gcc.podStore.Indexer = podInformer.GetIndexer() gcc.podController = podInformer.GetController() gcc.nodeStore.Store, gcc.nodeController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return gcc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return gcc.kubeClient.Core().Nodes().Watch(options) }, }, &api.Node{}, controller.NoResyncPeriodFunc(), cache.ResourceEventHandlerFuncs{}, ) return gcc }
// WaitForPodCreationServiceAccounts ensures that the service account needed for pod creation exists // and that the cache for the admission control that checks for pod tokens has caught up to allow // pod creation. func WaitForPodCreationServiceAccounts(client *kclient.Client, namespace string) error { if err := WaitForServiceAccounts(client, namespace, []string{bootstrappolicy.DefaultServiceAccountName}); err != nil { return err } testPod := &kapi.Pod{} testPod.GenerateName = "test" testPod.Spec.Containers = []kapi.Container{ { Name: "container", Image: "openshift/origin-pod:latest", }, } return wait.PollImmediate(time.Second, PodCreationWaitTimeout, func() (bool, error) { pod, err := client.Pods(namespace).Create(testPod) if err != nil { glog.Warningf("Error attempting to create test pod: %v", err) return false, nil } err = client.Pods(namespace).Delete(pod.Name, kapi.NewDeleteOptions(0)) if err != nil { return false, err } return true, nil }) }
func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (*internalclientset.Clientset, error)) error { if !cascade { if helper == nil { helper = resource.NewHelper(c, mapping) } return helper.Delete(namespace, name) } cs, err := clientsetFunc() if err != nil { return err } r, err := kubectl.ReaperFor(mapping.GroupVersionKind.GroupKind(), cs) if err != nil { if _, ok := err.(*kubectl.NoSuchReaperError); !ok { return err } return resource.NewHelper(c, mapping).Delete(namespace, name) } var options *api.DeleteOptions if gracePeriod >= 0 { options = api.NewDeleteOptions(int64(gracePeriod)) } if err := r.Stop(namespace, name, 2*time.Minute, options); err != nil { return err } return nil }
func validateDNSResults(f *framework.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 { 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 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. framework.Logf("DNS probes using %s succeeded\n", pod.Name) }
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 New(kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, threshold int) *GCController { if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } gcc := &GCController{ kubeClient: kubeClient, threshold: threshold, deletePod: func(namespace, name string) error { return kubeClient.Core().Pods(namespace).Delete(name, api.NewDeleteOptions(0)) }, } terminatedSelector := fields.ParseSelectorOrDie("status.phase!=" + string(api.PodPending) + ",status.phase!=" + string(api.PodRunning) + ",status.phase!=" + string(api.PodUnknown)) gcc.podStore.Indexer, gcc.podStoreSyncer = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{}, // We don't need to build a index for podStore here actually, but build one for consistency. // It will ensure that if people start making use of the podStore in more specific ways, // they'll get the benefits they expect. It will also reserve the name for future refactorings. cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return gcc }
// 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 *release_1_3.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, api.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, api.NewDeleteOptions(0)); err != nil { framework.Logf("Delete of pod %v:%v failed: %v", t.utilPod.Namespace, t.utilPod.Name, err) } }
func deletePods(kubeClient client.Interface, ns string, before unversioned.Time) (int64, error) { items, err := kubeClient.Pods(ns).List(unversioned.ListOptions{}) 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 }
// 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 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 deleteServiceOrFail(clientset *federation_release_1_4.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, api.NewDeleteOptions(0)) framework.ExpectNoError(err, "Error deleting service %q from namespace %q", serviceName, namespace) }
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) { options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{terminatedSelector}} return gcc.kubeClient.Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { options.FieldSelector.Selector = terminatedSelector return gcc.kubeClient.Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{}, ) return gcc }
func New(kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, threshold int) *GCController { gcc := &GCController{ kubeClient: kubeClient, threshold: threshold, deletePod: func(namespace, name string) error { return kubeClient.Legacy().Pods(namespace).Delete(name, api.NewDeleteOptions(0)) }, } terminatedSelector := fields.ParseSelectorOrDie("status.phase!=" + string(api.PodPending) + ",status.phase!=" + string(api.PodRunning) + ",status.phase!=" + string(api.PodUnknown)) gcc.podStore.Store, gcc.podStoreSyncer = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Legacy().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Legacy().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{}, ) return gcc }
func runLivenessTest(f *framework.Framework, pod *api.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, api.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) framework.ExpectNoError(err, fmt.Sprintf("getting pod %s in namespace %s", pod.Name, ns)) initialRestartCount := api.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) framework.ExpectNoError(err, fmt.Sprintf("getting pod %s", pod.Name)) restartCount := api.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) } }
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, longTestTimeout, 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, longTestTimeout, 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, longTestTimeout, 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, err: %v", pod, err) } else { glog.Fatalf("FAILED: (Scheduler probably didn't process deletion of 'phantom.bar') Pod never started running: err: %v, perr: %v", err, perr) } } glog.Info("Scheduler doesn't make phantom pods: test passed.") }
func TestGracefulStoreHandleFinalizers(t *testing.T) { EnableGarbageCollector = true initialGeneration := int64(1) defer func() { EnableGarbageCollector = false }() podWithFinalizer := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, Generation: initialGeneration}, Spec: api.PodSpec{NodeName: "machine"}, } testContext := api.WithNamespace(api.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) defaultDeleteStrategy := testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} defer destroyFunc() // create pod _, err := registry.Create(testContext, podWithFinalizer) if err != nil { t.Errorf("Unexpected error: %v", err) } // delete the pod with grace period=0, the pod should still exist because it has a finalizer _, err = registry.Delete(testContext, podWithFinalizer.Name, api.NewDeleteOptions(0)) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = registry.Get(testContext, podWithFinalizer.Name) if err != nil { t.Fatalf("Unexpected error: %v", err) } updatedPodWithFinalizer := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, Spec: api.PodSpec{NodeName: "machine"}, } _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } // the object should still exist, because it still has a finalizer _, err = registry.Get(testContext, podWithFinalizer.Name) if err != nil { t.Fatalf("Unexpected error: %v", err) } podWithNoFinalizer := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, Spec: api.PodSpec{NodeName: "anothermachine"}, } _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } // the pod should be removed, because its finalizer is removed _, err = registry.Get(testContext, podWithFinalizer.Name) if !errors.IsNotFound(err) { t.Fatalf("Unexpected error: %v", err) } }
// retry resets the status of the latest deployment to New, which will cause // the deployment to be retried. An error is returned if the deployment is not // currently in a failed state. func (o DeployOptions) retry(config *deployapi.DeploymentConfig) error { if config.Spec.Paused { return fmt.Errorf("cannot retry a paused deployment config") } if config.Status.LatestVersion == 0 { return fmt.Errorf("no deployments found for %s/%s", config.Namespace, config.Name) } // TODO: This implies that deploymentconfig.status.latestVersion is always synced. Currently, // that's the case because clients (oc, trigger controllers) are updating the status directly. // Clients should be acting either on spec or on annotations and status updates should be a // responsibility of the main controller. We need to start by unplugging this assumption from // our client tools. deploymentName := deployutil.LatestDeploymentNameForConfig(config) deployment, err := o.kubeClient.ReplicationControllers(config.Namespace).Get(deploymentName) if err != nil { if kerrors.IsNotFound(err) { return fmt.Errorf("unable to find the latest deployment (#%d).\nYou can start a new deployment with 'oc deploy --latest dc/%s'.", config.Status.LatestVersion, config.Name) } return err } if !deployutil.IsFailedDeployment(deployment) { message := fmt.Sprintf("#%d is %s; only failed deployments can be retried.\n", config.Status.LatestVersion, deployutil.DeploymentStatusFor(deployment)) if deployutil.IsCompleteDeployment(deployment) { message += fmt.Sprintf("You can start a new deployment with 'oc deploy --latest dc/%s'.", config.Name) } else { message += fmt.Sprintf("Optionally, you can cancel this deployment with 'oc deploy --cancel dc/%s'.", config.Name) } return fmt.Errorf(message) } // Delete the deployer pod as well as the deployment hooks pods, if any pods, err := o.kubeClient.Pods(config.Namespace).List(kapi.ListOptions{LabelSelector: deployutil.DeployerPodSelector(deploymentName)}) if err != nil { return fmt.Errorf("failed to list deployer/hook pods for deployment #%d: %v", config.Status.LatestVersion, err) } for _, pod := range pods.Items { err := o.kubeClient.Pods(pod.Namespace).Delete(pod.Name, kapi.NewDeleteOptions(0)) if err != nil { return fmt.Errorf("failed to delete deployer/hook pod %s for deployment #%d: %v", pod.Name, config.Status.LatestVersion, err) } } deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusNew) // clear out the cancellation flag as well as any previous status-reason annotation delete(deployment.Annotations, deployapi.DeploymentStatusReasonAnnotation) delete(deployment.Annotations, deployapi.DeploymentCancelledAnnotation) _, err = o.kubeClient.ReplicationControllers(deployment.Namespace).Update(deployment) if err != nil { return err } fmt.Fprintf(o.out, "Retried #%d\n", config.Status.LatestVersion) if o.follow { return o.getLogs(config) } fmt.Fprintf(o.out, "Use '%s logs -f dc/%s' to track its progress.\n", o.baseCommandName, config.Name) return nil }
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)) } }
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(api.ListOptions{}) framework.ExpectNoError(err) opt := api.NewDeleteOptions(0) for _, p := range pods.Items { framework.ExpectNoError(c.Pods(ns).Delete(p.ObjectMeta.Name, opt)) } }