Skip to content

Commit 2d491ac

Browse files
authored
Merge pull request kubernetes#82439 from smarterclayton/async_ns_cleanup
test/e2e: Delete test namespaces asynchronously
2 parents 75321b9 + 67283da commit 2d491ac

File tree

3 files changed

+1
-216
lines changed

3 files changed

+1
-216
lines changed

test/e2e/framework/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ go_library(
8888
"//test/e2e/system:go_default_library",
8989
"//test/utils:go_default_library",
9090
"//test/utils/image:go_default_library",
91-
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
9291
"//vendor/github.com/onsi/ginkgo:go_default_library",
9392
"//vendor/github.com/onsi/ginkgo/config:go_default_library",
9493
"//vendor/github.com/onsi/gomega:go_default_library",

test/e2e/framework/framework.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,7 @@ func (f *Framework) AfterEach() {
303303
if TestContext.DeleteNamespace && (TestContext.DeleteNamespaceOnFailure || !ginkgo.CurrentGinkgoTestDescription().Failed) {
304304
for _, ns := range f.namespacesToDelete {
305305
ginkgo.By(fmt.Sprintf("Destroying namespace %q for this suite.", ns.Name))
306-
timeout := DefaultNamespaceDeletionTimeout
307-
if f.NamespaceDeletionTimeout != 0 {
308-
timeout = f.NamespaceDeletionTimeout
309-
}
310-
if err := deleteNS(f.ClientSet, f.DynamicClient, ns.Name, timeout); err != nil {
306+
if err := f.ClientSet.CoreV1().Namespaces().Delete(ns.Name, nil); err != nil {
311307
if !apierrors.IsNotFound(err) {
312308
nsDeletionErrors[ns.Name] = err
313309
} else {

test/e2e/framework/util.go

Lines changed: 0 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import (
4040
"syscall"
4141
"time"
4242

43-
"github.com/davecgh/go-spew/spew"
4443
"golang.org/x/net/websocket"
4544
"k8s.io/klog"
4645

@@ -666,193 +665,6 @@ func CheckTestingNSDeletedExcept(c clientset.Interface, skip string) error {
666665
return fmt.Errorf("Waiting for terminating namespaces to be deleted timed out")
667666
}
668667

669-
// deleteNS deletes the provided namespace, waits for it to be completely deleted, and then checks
670-
// whether there are any pods remaining in a non-terminating state.
671-
func deleteNS(c clientset.Interface, dynamicClient dynamic.Interface, namespace string, timeout time.Duration) error {
672-
startTime := time.Now()
673-
if err := c.CoreV1().Namespaces().Delete(namespace, nil); err != nil {
674-
return err
675-
}
676-
677-
// wait for namespace to delete or timeout.
678-
var lastNamespace *v1.Namespace
679-
err := wait.PollImmediate(2*time.Second, timeout, func() (bool, error) {
680-
var err error
681-
lastNamespace, err = c.CoreV1().Namespaces().Get(namespace, metav1.GetOptions{})
682-
if err != nil {
683-
if apierrs.IsNotFound(err) {
684-
return true, nil
685-
}
686-
Logf("Error while waiting for namespace to be terminated: %v", err)
687-
return false, nil
688-
}
689-
return false, nil
690-
})
691-
692-
// verify there is no more remaining content in the namespace
693-
remainingContent, cerr := hasRemainingContent(c, dynamicClient, namespace)
694-
if cerr != nil {
695-
return cerr
696-
}
697-
698-
// if content remains, let's dump information about the namespace, and system for flake debugging.
699-
remainingPods := 0
700-
missingTimestamp := 0
701-
if remainingContent {
702-
// log information about namespace, and set of namespaces in api server to help flake detection
703-
logNamespace(c, namespace)
704-
logNamespaces(c, namespace)
705-
706-
// if we can, check if there were pods remaining with no timestamp.
707-
remainingPods, missingTimestamp, _ = e2epod.CountRemainingPods(c, namespace)
708-
}
709-
710-
// a timeout waiting for namespace deletion happened!
711-
if err != nil {
712-
// namespaces now have conditions that are useful for debugging generic resources and finalizers
713-
Logf("namespace did not cleanup: %s", spew.Sdump(lastNamespace))
714-
715-
// some content remains in the namespace
716-
if remainingContent {
717-
// pods remain
718-
if remainingPods > 0 {
719-
if missingTimestamp != 0 {
720-
// pods remained, but were not undergoing deletion (namespace controller is probably culprit)
721-
return fmt.Errorf("namespace %v was not deleted with limit: %v, pods remaining: %v, pods missing deletion timestamp: %v", namespace, err, remainingPods, missingTimestamp)
722-
}
723-
// but they were all undergoing deletion (kubelet is probably culprit, check NodeLost)
724-
return fmt.Errorf("namespace %v was not deleted with limit: %v, pods remaining: %v", namespace, err, remainingPods)
725-
}
726-
// other content remains (namespace controller is probably screwed up)
727-
return fmt.Errorf("namespace %v was not deleted with limit: %v, namespaced content other than pods remain", namespace, err)
728-
}
729-
// no remaining content, but namespace was not deleted (namespace controller is probably wedged)
730-
return fmt.Errorf("namespace %v was not deleted with limit: %v, namespace is empty but is not yet removed", namespace, err)
731-
}
732-
Logf("namespace %v deletion completed in %s", namespace, time.Since(startTime))
733-
return nil
734-
}
735-
736-
// logNamespaces logs the number of namespaces by phase
737-
// namespace is the namespace the test was operating against that failed to delete so it can be grepped in logs
738-
func logNamespaces(c clientset.Interface, namespace string) {
739-
namespaceList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{})
740-
if err != nil {
741-
Logf("namespace: %v, unable to list namespaces: %v", namespace, err)
742-
return
743-
}
744-
745-
numActive := 0
746-
numTerminating := 0
747-
for _, namespace := range namespaceList.Items {
748-
if namespace.Status.Phase == v1.NamespaceActive {
749-
numActive++
750-
} else {
751-
numTerminating++
752-
}
753-
}
754-
Logf("namespace: %v, total namespaces: %v, active: %v, terminating: %v", namespace, len(namespaceList.Items), numActive, numTerminating)
755-
}
756-
757-
// logNamespace logs detail about a namespace
758-
func logNamespace(c clientset.Interface, namespace string) {
759-
ns, err := c.CoreV1().Namespaces().Get(namespace, metav1.GetOptions{})
760-
if err != nil {
761-
if apierrs.IsNotFound(err) {
762-
Logf("namespace: %v no longer exists", namespace)
763-
return
764-
}
765-
Logf("namespace: %v, unable to get namespace due to error: %v", namespace, err)
766-
return
767-
}
768-
Logf("namespace: %v, DeletionTimetamp: %v, Finalizers: %v, Phase: %v", ns.Name, ns.DeletionTimestamp, ns.Spec.Finalizers, ns.Status.Phase)
769-
}
770-
771-
// isDynamicDiscoveryError returns true if the error is a group discovery error
772-
// only for groups expected to be created/deleted dynamically during e2e tests
773-
func isDynamicDiscoveryError(err error) bool {
774-
if !discovery.IsGroupDiscoveryFailedError(err) {
775-
return false
776-
}
777-
discoveryErr := err.(*discovery.ErrGroupDiscoveryFailed)
778-
for gv := range discoveryErr.Groups {
779-
switch gv.Group {
780-
case "mygroup.example.com":
781-
// custom_resource_definition
782-
// garbage_collector
783-
case "wardle.k8s.io":
784-
// aggregator
785-
case "metrics.k8s.io":
786-
// aggregated metrics server add-on, no persisted resources
787-
default:
788-
Logf("discovery error for unexpected group: %#v", gv)
789-
return false
790-
}
791-
}
792-
return true
793-
}
794-
795-
// hasRemainingContent checks if there is remaining content in the namespace via API discovery
796-
func hasRemainingContent(c clientset.Interface, dynamicClient dynamic.Interface, namespace string) (bool, error) {
797-
// some tests generate their own framework.Client rather than the default
798-
// TODO: ensure every test call has a configured dynamicClient
799-
if dynamicClient == nil {
800-
return false, nil
801-
}
802-
803-
// find out what content is supported on the server
804-
// Since extension apiserver is not always available, e.g. metrics server sometimes goes down,
805-
// add retry here.
806-
resources, err := waitForServerPreferredNamespacedResources(c.Discovery(), 30*time.Second)
807-
if err != nil {
808-
return false, err
809-
}
810-
resources = discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"list", "delete"}}, resources)
811-
groupVersionResources, err := discovery.GroupVersionResources(resources)
812-
if err != nil {
813-
return false, err
814-
}
815-
816-
// TODO: temporary hack for https://github.com/kubernetes/kubernetes/issues/31798
817-
ignoredResources := sets.NewString("bindings")
818-
819-
contentRemaining := false
820-
821-
// dump how many of resource type is on the server in a log.
822-
for gvr := range groupVersionResources {
823-
// get a client for this group version...
824-
dynamicClient := dynamicClient.Resource(gvr).Namespace(namespace)
825-
if err != nil {
826-
// not all resource types support list, so some errors here are normal depending on the resource type.
827-
Logf("namespace: %s, unable to get client - gvr: %v, error: %v", namespace, gvr, err)
828-
continue
829-
}
830-
// get the api resource
831-
apiResource := metav1.APIResource{Name: gvr.Resource, Namespaced: true}
832-
if ignoredResources.Has(gvr.Resource) {
833-
Logf("namespace: %s, resource: %s, ignored listing per whitelist", namespace, apiResource.Name)
834-
continue
835-
}
836-
unstructuredList, err := dynamicClient.List(metav1.ListOptions{})
837-
if err != nil {
838-
// not all resources support list, so we ignore those
839-
if apierrs.IsMethodNotSupported(err) || apierrs.IsNotFound(err) || apierrs.IsForbidden(err) {
840-
continue
841-
}
842-
// skip unavailable servers
843-
if apierrs.IsServiceUnavailable(err) {
844-
continue
845-
}
846-
return false, err
847-
}
848-
if len(unstructuredList.Items) > 0 {
849-
Logf("namespace: %s, resource: %s, items remaining: %v", namespace, apiResource.Name, len(unstructuredList.Items))
850-
contentRemaining = true
851-
}
852-
}
853-
return contentRemaining, nil
854-
}
855-
856668
// ContainerInitInvariant checks for an init containers are initialized and invariant on both older and newer.
857669
func ContainerInitInvariant(older, newer runtime.Object) error {
858670
oldPod := older.(*v1.Pod)
@@ -3051,28 +2863,6 @@ func DsFromManifest(url string) (*appsv1.DaemonSet, error) {
30512863
return &ds, nil
30522864
}
30532865

3054-
// waitForServerPreferredNamespacedResources waits until server preferred namespaced resources could be successfully discovered.
3055-
// TODO: Fix https://github.com/kubernetes/kubernetes/issues/55768 and remove the following retry.
3056-
func waitForServerPreferredNamespacedResources(d discovery.DiscoveryInterface, timeout time.Duration) ([]*metav1.APIResourceList, error) {
3057-
Logf("Waiting up to %v for server preferred namespaced resources to be successfully discovered", timeout)
3058-
var resources []*metav1.APIResourceList
3059-
if err := wait.PollImmediate(Poll, timeout, func() (bool, error) {
3060-
var err error
3061-
resources, err = d.ServerPreferredNamespacedResources()
3062-
if err == nil || isDynamicDiscoveryError(err) {
3063-
return true, nil
3064-
}
3065-
if !discovery.IsGroupDiscoveryFailedError(err) {
3066-
return false, err
3067-
}
3068-
Logf("Error discoverying server preferred namespaced resources: %v, retrying in %v.", err, Poll)
3069-
return false, nil
3070-
}); err != nil {
3071-
return nil, err
3072-
}
3073-
return resources, nil
3074-
}
3075-
30762866
// WaitForPersistentVolumeClaimDeleted waits for a PersistentVolumeClaim to be removed from the system until timeout occurs, whichever comes first.
30772867
func WaitForPersistentVolumeClaimDeleted(c clientset.Interface, ns string, pvcName string, Poll, timeout time.Duration) error {
30782868
Logf("Waiting up to %v for PersistentVolumeClaim %s to be removed", timeout, pvcName)

0 commit comments

Comments
 (0)