...

Source file src/k8s.io/kubernetes/test/e2e/storage/pvc_protection.go

Documentation: k8s.io/kubernetes/test/e2e/storage

     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 storage
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/onsi/ginkgo/v2"
    23  	"github.com/onsi/gomega"
    24  
    25  	"fmt"
    26  	"time"
    27  
    28  	v1 "k8s.io/api/core/v1"
    29  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	clientset "k8s.io/client-go/kubernetes"
    32  	volumeutil "k8s.io/kubernetes/pkg/volume/util"
    33  	"k8s.io/kubernetes/test/e2e/framework"
    34  	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
    35  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    36  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    37  	"k8s.io/kubernetes/test/e2e/storage/testsuites"
    38  	"k8s.io/kubernetes/test/e2e/storage/utils"
    39  	admissionapi "k8s.io/pod-security-admission/api"
    40  )
    41  
    42  const (
    43  	// claimDeletingTimeout is How long claims have to become deleted.
    44  	claimDeletingTimeout = 3 * time.Minute
    45  )
    46  
    47  // waitForPersistentVolumeClaimDeleted waits for a PersistentVolumeClaim to be removed from the system until timeout occurs, whichever comes first.
    48  func waitForPersistentVolumeClaimDeleted(ctx context.Context, c clientset.Interface, ns string, pvcName string, Poll, timeout time.Duration) error {
    49  	framework.Logf("Waiting up to %v for PersistentVolumeClaim %s to be removed", timeout, pvcName)
    50  	for start := time.Now(); time.Since(start) < timeout; time.Sleep(Poll) {
    51  		_, err := c.CoreV1().PersistentVolumeClaims(ns).Get(ctx, pvcName, metav1.GetOptions{})
    52  		if err != nil {
    53  			if apierrors.IsNotFound(err) {
    54  				framework.Logf("Claim %q in namespace %q doesn't exist in the system", pvcName, ns)
    55  				return nil
    56  			}
    57  			framework.Logf("Failed to get claim %q in namespace %q, retrying in %v. Error: %v", pvcName, ns, Poll, err)
    58  		}
    59  	}
    60  	return fmt.Errorf("PersistentVolumeClaim %s is not removed from the system within %v", pvcName, timeout)
    61  }
    62  
    63  var _ = utils.SIGDescribe("PVC Protection", func() {
    64  	var (
    65  		client                  clientset.Interface
    66  		nameSpace               string
    67  		err                     error
    68  		pvc                     *v1.PersistentVolumeClaim
    69  		pvcCreatedAndNotDeleted bool
    70  		pod                     *v1.Pod
    71  	)
    72  
    73  	f := framework.NewDefaultFramework("pvc-protection")
    74  	f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
    75  	ginkgo.BeforeEach(func(ctx context.Context) {
    76  		client = f.ClientSet
    77  		nameSpace = f.Namespace.Name
    78  		framework.ExpectNoError(e2enode.WaitForAllNodesSchedulable(ctx, client, f.Timeouts.NodeSchedulable))
    79  
    80  		ginkgo.By("Creating a PVC")
    81  		prefix := "pvc-protection"
    82  		e2epv.SkipIfNoDefaultStorageClass(ctx, client)
    83  		t := testsuites.StorageClassTest{
    84  			Timeouts:  f.Timeouts,
    85  			ClaimSize: "1Gi",
    86  		}
    87  		pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
    88  			NamePrefix: prefix,
    89  			ClaimSize:  t.ClaimSize,
    90  			VolumeMode: &t.VolumeMode,
    91  		}, nameSpace)
    92  		pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
    93  		framework.ExpectNoError(err, "Error creating PVC")
    94  		pvcCreatedAndNotDeleted = true
    95  
    96  		ginkgo.By("Creating a Pod that becomes Running and therefore is actively using the PVC")
    97  		pvcClaims := []*v1.PersistentVolumeClaim{pvc}
    98  		pod, err = e2epod.CreatePod(ctx, client, nameSpace, nil, pvcClaims, f.NamespacePodSecurityLevel, "")
    99  		framework.ExpectNoError(err, "While creating pod that uses the PVC or waiting for the Pod to become Running")
   100  
   101  		ginkgo.By("Waiting for PVC to become Bound")
   102  		err = e2epv.WaitForPersistentVolumeClaimPhase(ctx, v1.ClaimBound, client, nameSpace, pvc.Name, framework.Poll, f.Timeouts.ClaimBound)
   103  		framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
   104  
   105  		ginkgo.By("Checking that PVC Protection finalizer is set")
   106  		pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
   107  		framework.ExpectNoError(err, "While getting PVC status")
   108  		gomega.Expect(pvc.ObjectMeta.Finalizers).Should(gomega.ContainElement(volumeutil.PVCProtectionFinalizer), "PVC Protection finalizer(%v) is not set in %v", volumeutil.PVCProtectionFinalizer, pvc.ObjectMeta.Finalizers)
   109  	})
   110  
   111  	ginkgo.AfterEach(func(ctx context.Context) {
   112  		if pvcCreatedAndNotDeleted {
   113  			e2epv.DeletePersistentVolumeClaim(ctx, client, pvc.Name, nameSpace)
   114  		}
   115  	})
   116  
   117  	ginkgo.It("Verify \"immediate\" deletion of a PVC that is not in active use by a pod", func(ctx context.Context) {
   118  		ginkgo.By("Deleting the pod using the PVC")
   119  		err = e2epod.DeletePodWithWait(ctx, client, pod)
   120  		framework.ExpectNoError(err, "Error terminating and deleting pod")
   121  
   122  		ginkgo.By("Deleting the PVC")
   123  		err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, *metav1.NewDeleteOptions(0))
   124  		framework.ExpectNoError(err, "Error deleting PVC")
   125  		waitForPersistentVolumeClaimDeleted(ctx, client, pvc.Namespace, pvc.Name, framework.Poll, claimDeletingTimeout)
   126  		pvcCreatedAndNotDeleted = false
   127  	})
   128  
   129  	ginkgo.It("Verify that PVC in active use by a pod is not removed immediately", func(ctx context.Context) {
   130  		ginkgo.By("Deleting the PVC, however, the PVC must not be removed from the system as it's in active use by a pod")
   131  		err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, *metav1.NewDeleteOptions(0))
   132  		framework.ExpectNoError(err, "Error deleting PVC")
   133  
   134  		ginkgo.By("Checking that the PVC status is Terminating")
   135  		pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
   136  		framework.ExpectNoError(err, "While checking PVC status")
   137  		gomega.Expect(pvc.ObjectMeta.DeletionTimestamp).ToNot(gomega.BeNil())
   138  
   139  		ginkgo.By("Deleting the pod that uses the PVC")
   140  		err = e2epod.DeletePodWithWait(ctx, client, pod)
   141  		framework.ExpectNoError(err, "Error terminating and deleting pod")
   142  
   143  		ginkgo.By("Checking that the PVC is automatically removed from the system because it's no longer in active use by a pod")
   144  		waitForPersistentVolumeClaimDeleted(ctx, client, pvc.Namespace, pvc.Name, framework.Poll, claimDeletingTimeout)
   145  		pvcCreatedAndNotDeleted = false
   146  	})
   147  
   148  	ginkgo.It("Verify that scheduling of a pod that uses PVC that is being deleted fails and the pod becomes Unschedulable", func(ctx context.Context) {
   149  		ginkgo.By("Deleting the PVC, however, the PVC must not be removed from the system as it's in active use by a pod")
   150  		err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Delete(ctx, pvc.Name, *metav1.NewDeleteOptions(0))
   151  		framework.ExpectNoError(err, "Error deleting PVC")
   152  
   153  		ginkgo.By("Checking that the PVC status is Terminating")
   154  		pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
   155  		framework.ExpectNoError(err, "While checking PVC status")
   156  		gomega.Expect(pvc.ObjectMeta.DeletionTimestamp).ToNot(gomega.BeNil())
   157  
   158  		ginkgo.By("Creating second Pod whose scheduling fails because it uses a PVC that is being deleted")
   159  		secondPod, err2 := e2epod.CreateUnschedulablePod(ctx, client, nameSpace, nil, []*v1.PersistentVolumeClaim{pvc}, f.NamespacePodSecurityLevel, "")
   160  		framework.ExpectNoError(err2, "While creating second pod that uses a PVC that is being deleted and that is Unschedulable")
   161  
   162  		ginkgo.By("Deleting the second pod that uses the PVC that is being deleted")
   163  		err = e2epod.DeletePodWithWait(ctx, client, secondPod)
   164  		framework.ExpectNoError(err, "Error terminating and deleting pod")
   165  
   166  		ginkgo.By("Checking again that the PVC status is Terminating")
   167  		pvc, err = client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(ctx, pvc.Name, metav1.GetOptions{})
   168  		framework.ExpectNoError(err, "While checking PVC status")
   169  		gomega.Expect(pvc.ObjectMeta.DeletionTimestamp).ToNot(gomega.BeNil())
   170  
   171  		ginkgo.By("Deleting the first pod that uses the PVC")
   172  		err = e2epod.DeletePodWithWait(ctx, client, pod)
   173  		framework.ExpectNoError(err, "Error terminating and deleting pod")
   174  
   175  		ginkgo.By("Checking that the PVC is automatically removed from the system because it's no longer in active use by a pod")
   176  		waitForPersistentVolumeClaimDeleted(ctx, client, pvc.Namespace, pvc.Name, framework.Poll, claimDeletingTimeout)
   177  		pvcCreatedAndNotDeleted = false
   178  	})
   179  })
   180  

View as plain text