...

Source file src/k8s.io/kubernetes/test/integration/garbagecollector/cluster_scoped_owner_test.go

Documentation: k8s.io/kubernetes/test/integration/garbagecollector

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package garbagecollector
    18  
    19  import (
    20  	"context"
    21  	"io"
    22  	"net/http"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"k8s.io/api/core/v1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	"k8s.io/apimachinery/pkg/api/resource"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/apimachinery/pkg/util/wait"
    33  	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
    34  	"k8s.io/kubernetes/test/integration/framework"
    35  )
    36  
    37  type roundTripFunc func(req *http.Request) (*http.Response, error)
    38  
    39  func (w roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
    40  	return w(req)
    41  }
    42  
    43  type readDelayer struct {
    44  	delay time.Duration
    45  	io.ReadCloser
    46  }
    47  
    48  func (b *readDelayer) Read(p []byte) (n int, err error) {
    49  	defer time.Sleep(b.delay)
    50  	return b.ReadCloser.Read(p)
    51  }
    52  
    53  func TestClusterScopedOwners(t *testing.T) {
    54  	// Start the test server and wrap the client to delay PV watch responses
    55  	server := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
    56  	server.ClientConfig.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
    57  		return roundTripFunc(func(req *http.Request) (*http.Response, error) {
    58  			if req.URL.Query().Get("watch") != "true" || !strings.Contains(req.URL.String(), "persistentvolumes") {
    59  				return rt.RoundTrip(req)
    60  			}
    61  			resp, err := rt.RoundTrip(req)
    62  			if err != nil {
    63  				return resp, err
    64  			}
    65  			resp.Body = &readDelayer{30 * time.Second, resp.Body}
    66  			return resp, err
    67  		})
    68  	}
    69  	ctx := setupWithServer(t, server, 5)
    70  	defer ctx.tearDown()
    71  
    72  	_, clientSet := ctx.gc, ctx.clientSet
    73  
    74  	ns := createNamespaceOrDie("gc-cluster-scope-deletion", clientSet, t)
    75  	defer deleteNamespaceOrDie(ns.Name, clientSet, t)
    76  
    77  	t.Log("Create a pair of objects")
    78  	pv, err := clientSet.CoreV1().PersistentVolumes().Create(context.TODO(), &v1.PersistentVolume{
    79  		ObjectMeta: metav1.ObjectMeta{Name: "pv-valid"},
    80  		Spec: v1.PersistentVolumeSpec{
    81  			PersistentVolumeSource: v1.PersistentVolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/foo"}},
    82  			Capacity:               v1.ResourceList{v1.ResourceStorage: resource.MustParse("1Gi")},
    83  			AccessModes:            []v1.PersistentVolumeAccessMode{v1.ReadWriteMany},
    84  		},
    85  	}, metav1.CreateOptions{})
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	if _, err := clientSet.CoreV1().ConfigMaps(ns.Name).Create(context.TODO(), &v1.ConfigMap{
    90  		ObjectMeta: metav1.ObjectMeta{
    91  			Name:            "cm-valid",
    92  			OwnerReferences: []metav1.OwnerReference{{Kind: "PersistentVolume", APIVersion: "v1", Name: pv.Name, UID: pv.UID}},
    93  		},
    94  	}, metav1.CreateOptions{}); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	t.Log("Create a namespaced object with a missing parent")
    99  	if _, err := clientSet.CoreV1().ConfigMaps(ns.Name).Create(context.TODO(), &v1.ConfigMap{
   100  		ObjectMeta: metav1.ObjectMeta{
   101  			Name:            "cm-missing",
   102  			Labels:          map[string]string{"missing": "true"},
   103  			OwnerReferences: []metav1.OwnerReference{{Kind: "PersistentVolume", APIVersion: "v1", Name: "missing-name", UID: types.UID("missing-uid")}},
   104  		},
   105  	}, metav1.CreateOptions{}); err != nil {
   106  		t.Fatal(err)
   107  	}
   108  
   109  	t.Log("Create a namespaced object with a missing type parent")
   110  	if _, err := clientSet.CoreV1().ConfigMaps(ns.Name).Create(context.TODO(), &v1.ConfigMap{
   111  		ObjectMeta: metav1.ObjectMeta{
   112  			Name:            "cm-invalid",
   113  			OwnerReferences: []metav1.OwnerReference{{Kind: "UnknownType", APIVersion: "unknown.group/v1", Name: "invalid-name", UID: types.UID("invalid-uid")}},
   114  		},
   115  	}, metav1.CreateOptions{}); err != nil {
   116  		t.Fatal(err)
   117  	}
   118  
   119  	// wait for deletable children to go away
   120  	if err := wait.Poll(5*time.Second, 300*time.Second, func() (bool, error) {
   121  		_, err := clientSet.CoreV1().ConfigMaps(ns.Name).Get(context.TODO(), "cm-missing", metav1.GetOptions{})
   122  		switch {
   123  		case apierrors.IsNotFound(err):
   124  			return true, nil
   125  		case err != nil:
   126  			return false, err
   127  		default:
   128  			t.Logf("cm with missing parent still exists, retrying")
   129  			return false, nil
   130  		}
   131  	}); err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	t.Logf("deletable children removed")
   135  
   136  	// Give time for blocked children to be incorrectly cleaned up
   137  	time.Sleep(5 * time.Second)
   138  
   139  	// ensure children with unverifiable parents don't get reaped
   140  	if _, err := clientSet.CoreV1().ConfigMaps(ns.Name).Get(context.TODO(), "cm-invalid", metav1.GetOptions{}); err != nil {
   141  		t.Fatalf("child with invalid ownerRef is unexpectedly missing: %v", err)
   142  	}
   143  
   144  	// ensure children with present parents don't get reaped
   145  	if _, err := clientSet.CoreV1().ConfigMaps(ns.Name).Get(context.TODO(), "cm-valid", metav1.GetOptions{}); err != nil {
   146  		t.Fatalf("child with valid ownerRef is unexpectedly missing: %v", err)
   147  	}
   148  }
   149  

View as plain text