k8s.io/kubernetes@v1.29.3/test/e2e/upgrades/storage/volume_mode.go (about)

     1  /*
     2  Copyright 2018 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  	"fmt"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/version"
    27  	"k8s.io/kubernetes/test/e2e/framework"
    28  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    29  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    30  	e2evolume "k8s.io/kubernetes/test/e2e/framework/volume"
    31  	storageutils "k8s.io/kubernetes/test/e2e/storage/utils"
    32  	"k8s.io/kubernetes/test/e2e/upgrades"
    33  
    34  	"github.com/onsi/ginkgo/v2"
    35  )
    36  
    37  const devicePath = "/mnt/volume1"
    38  
    39  // VolumeModeDowngradeTest tests that a VolumeMode Block PV is not mistakenly
    40  // formatted and mounted like a nil/Filesystem PV after a downgrade to a version
    41  // where the BlockVolume feature is disabled
    42  type VolumeModeDowngradeTest struct {
    43  	pv  *v1.PersistentVolume
    44  	pvc *v1.PersistentVolumeClaim
    45  	pod *v1.Pod
    46  }
    47  
    48  // Name returns the tracking name of the test.
    49  func (VolumeModeDowngradeTest) Name() string {
    50  	return "[sig-storage] volume-mode-downgrade"
    51  }
    52  
    53  // Skip returns true when this test can be skipped.
    54  func (t *VolumeModeDowngradeTest) Skip(upgCtx upgrades.UpgradeContext) bool {
    55  	if !framework.ProviderIs("openstack", "gce", "aws", "gke", "vsphere", "azure") {
    56  		return true
    57  	}
    58  
    59  	// Only run when downgrading from >= 1.13 to < 1.13
    60  	blockVersion := version.MustParseSemantic("1.13.0-alpha.0")
    61  	if upgCtx.Versions[0].Version.LessThan(blockVersion) {
    62  		return true
    63  	}
    64  	if !upgCtx.Versions[1].Version.LessThan(blockVersion) {
    65  		return true
    66  	}
    67  
    68  	return false
    69  }
    70  
    71  // Setup creates a block pv and then verifies that a pod can consume it.  The pod writes data to the volume.
    72  func (t *VolumeModeDowngradeTest) Setup(ctx context.Context, f *framework.Framework) {
    73  
    74  	var err error
    75  
    76  	cs := f.ClientSet
    77  	ns := f.Namespace.Name
    78  
    79  	ginkgo.By("Creating a PVC")
    80  	block := v1.PersistentVolumeBlock
    81  	pvcConfig := e2epv.PersistentVolumeClaimConfig{
    82  		StorageClassName: nil,
    83  		VolumeMode:       &block,
    84  	}
    85  	t.pvc = e2epv.MakePersistentVolumeClaim(pvcConfig, ns)
    86  	t.pvc, err = e2epv.CreatePVC(ctx, cs, ns, t.pvc)
    87  	framework.ExpectNoError(err)
    88  
    89  	err = e2epv.WaitForPersistentVolumeClaimPhase(ctx, v1.ClaimBound, cs, ns, t.pvc.Name, framework.Poll, framework.ClaimProvisionTimeout)
    90  	framework.ExpectNoError(err)
    91  
    92  	t.pvc, err = cs.CoreV1().PersistentVolumeClaims(t.pvc.Namespace).Get(ctx, t.pvc.Name, metav1.GetOptions{})
    93  	framework.ExpectNoError(err)
    94  
    95  	t.pv, err = cs.CoreV1().PersistentVolumes().Get(ctx, t.pvc.Spec.VolumeName, metav1.GetOptions{})
    96  	framework.ExpectNoError(err)
    97  
    98  	ginkgo.By("Consuming the PVC before downgrade")
    99  	podConfig := e2epod.Config{
   100  		NS:           ns,
   101  		PVCs:         []*v1.PersistentVolumeClaim{t.pvc},
   102  		SeLinuxLabel: e2epv.SELinuxLabel,
   103  	}
   104  	t.pod, err = e2epod.CreateSecPod(ctx, cs, &podConfig, framework.PodStartTimeout)
   105  	framework.ExpectNoError(err)
   106  
   107  	ginkgo.By("Checking if PV exists as expected volume mode")
   108  	e2evolume.CheckVolumeModeOfPath(f, t.pod, block, devicePath)
   109  
   110  	ginkgo.By("Checking if read/write to PV works properly")
   111  	storageutils.CheckReadWriteToPath(f, t.pod, block, devicePath)
   112  }
   113  
   114  // Test waits for the downgrade to complete, and then verifies that a pod can no
   115  // longer consume the pv as it is not mapped nor mounted into the pod
   116  func (t *VolumeModeDowngradeTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
   117  	ginkgo.By("Waiting for downgrade to finish")
   118  	<-done
   119  
   120  	ginkgo.By("Verifying that nothing exists at the device path in the pod")
   121  	e2evolume.VerifyExecInPodFail(f, t.pod, fmt.Sprintf("test -e %s", devicePath), 1)
   122  }
   123  
   124  // Teardown cleans up any remaining resources.
   125  func (t *VolumeModeDowngradeTest) Teardown(ctx context.Context, f *framework.Framework) {
   126  	ginkgo.By("Deleting the pod")
   127  	framework.ExpectNoError(e2epod.DeletePodWithWait(ctx, f.ClientSet, t.pod))
   128  
   129  	ginkgo.By("Deleting the PVC")
   130  	framework.ExpectNoError(f.ClientSet.CoreV1().PersistentVolumeClaims(t.pvc.Namespace).Delete(ctx, t.pvc.Name, metav1.DeleteOptions{}))
   131  
   132  	ginkgo.By("Waiting for the PV to be deleted")
   133  	framework.ExpectNoError(e2epv.WaitForPersistentVolumeDeleted(ctx, f.ClientSet, t.pv.Name, 5*time.Second, 20*time.Minute))
   134  }