k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/storage/ubernetes_lite_volumes.go (about)

     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  	"fmt"
    22  	"sync"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  	v1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    28  	"k8s.io/apimachinery/pkg/util/sets"
    29  	clientset "k8s.io/client-go/kubernetes"
    30  	"k8s.io/kubernetes/test/e2e/framework"
    31  	e2enode "k8s.io/kubernetes/test/e2e/framework/node"
    32  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    33  	e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
    34  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    35  	"k8s.io/kubernetes/test/e2e/storage/utils"
    36  	imageutils "k8s.io/kubernetes/test/utils/image"
    37  	admissionapi "k8s.io/pod-security-admission/api"
    38  )
    39  
    40  var _ = utils.SIGDescribe("Multi-AZ Cluster Volumes", func() {
    41  	f := framework.NewDefaultFramework("multi-az")
    42  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    43  	var zoneCount int
    44  	var err error
    45  	image := imageutils.GetE2EImage(imageutils.Agnhost)
    46  	ginkgo.BeforeEach(func(ctx context.Context) {
    47  		e2eskipper.SkipUnlessProviderIs("gce", "gke")
    48  		if zoneCount <= 0 {
    49  			zoneCount, err = getZoneCount(ctx, f.ClientSet)
    50  			framework.ExpectNoError(err)
    51  		}
    52  		ginkgo.By(fmt.Sprintf("Checking for multi-zone cluster.  Zone count = %d", zoneCount))
    53  		msg := fmt.Sprintf("Zone count is %d, only run for multi-zone clusters, skipping test", zoneCount)
    54  		e2eskipper.SkipUnlessAtLeast(zoneCount, 2, msg)
    55  		// TODO: SkipUnlessDefaultScheduler() // Non-default schedulers might not spread
    56  	})
    57  	ginkgo.It("should schedule pods in the same zones as statically provisioned PVs", func(ctx context.Context) {
    58  		PodsUseStaticPVsOrFail(ctx, f, (2*zoneCount)+1, image)
    59  	})
    60  })
    61  
    62  // Return the number of zones in which we have nodes in this cluster.
    63  func getZoneCount(ctx context.Context, c clientset.Interface) (int, error) {
    64  	zoneNames, err := e2enode.GetSchedulableClusterZones(ctx, c)
    65  	if err != nil {
    66  		return -1, err
    67  	}
    68  	return len(zoneNames), nil
    69  }
    70  
    71  type staticPVTestConfig struct {
    72  	pvSource *v1.PersistentVolumeSource
    73  	pv       *v1.PersistentVolume
    74  	pvc      *v1.PersistentVolumeClaim
    75  	pod      *v1.Pod
    76  }
    77  
    78  // PodsUseStaticPVsOrFail Check that the pods using statically
    79  // created PVs get scheduled to the same zone that the PV is in.
    80  func PodsUseStaticPVsOrFail(ctx context.Context, f *framework.Framework, podCount int, image string) {
    81  	var err error
    82  	c := f.ClientSet
    83  	ns := f.Namespace.Name
    84  
    85  	zones, err := e2enode.GetSchedulableClusterZones(ctx, c)
    86  	framework.ExpectNoError(err)
    87  	zonelist := sets.List(zones)
    88  	ginkgo.By("Creating static PVs across zones")
    89  	configs := make([]*staticPVTestConfig, podCount)
    90  	for i := range configs {
    91  		configs[i] = &staticPVTestConfig{}
    92  	}
    93  
    94  	ginkgo.DeferCleanup(func(ctx context.Context) {
    95  		ginkgo.By("Cleaning up pods and PVs")
    96  		for _, config := range configs {
    97  			e2epod.DeletePodOrFail(ctx, c, ns, config.pod.Name)
    98  		}
    99  		var wg sync.WaitGroup
   100  		wg.Add(len(configs))
   101  		for i := range configs {
   102  			go func(config *staticPVTestConfig) {
   103  				defer ginkgo.GinkgoRecover()
   104  				defer wg.Done()
   105  				err := e2epod.WaitForPodNotFoundInNamespace(ctx, c, config.pod.Name, ns, f.Timeouts.PodDelete)
   106  				framework.ExpectNoError(err, "while waiting for pod to disappear")
   107  				errs := e2epv.PVPVCCleanup(ctx, c, ns, config.pv, config.pvc)
   108  				framework.ExpectNoError(utilerrors.NewAggregate(errs), "while cleaning up PVs and PVCs")
   109  				err = e2epv.DeletePVSource(ctx, config.pvSource)
   110  				framework.ExpectNoError(err, "while deleting PVSource")
   111  			}(configs[i])
   112  		}
   113  		wg.Wait()
   114  	})
   115  
   116  	for i, config := range configs {
   117  		zone := zonelist[i%len(zones)]
   118  		config.pvSource, err = e2epv.CreatePVSource(ctx, zone)
   119  		framework.ExpectNoError(err)
   120  
   121  		pvConfig := e2epv.PersistentVolumeConfig{
   122  			NamePrefix: "multizone-pv",
   123  			PVSource:   *config.pvSource,
   124  			Prebind:    nil,
   125  		}
   126  		className := ""
   127  		pvcConfig := e2epv.PersistentVolumeClaimConfig{StorageClassName: &className}
   128  
   129  		config.pv, config.pvc, err = e2epv.CreatePVPVC(ctx, c, f.Timeouts, pvConfig, pvcConfig, ns, true)
   130  		framework.ExpectNoError(err)
   131  	}
   132  
   133  	ginkgo.By("Waiting for all PVCs to be bound")
   134  	for _, config := range configs {
   135  		e2epv.WaitOnPVandPVC(ctx, c, f.Timeouts, ns, config.pv, config.pvc)
   136  	}
   137  
   138  	ginkgo.By("Creating pods for each static PV")
   139  	for _, config := range configs {
   140  		podConfig := e2epod.MakePod(ns, nil, []*v1.PersistentVolumeClaim{config.pvc}, f.NamespacePodSecurityLevel, "")
   141  		config.pod, err = c.CoreV1().Pods(ns).Create(ctx, podConfig, metav1.CreateOptions{})
   142  		framework.ExpectNoError(err)
   143  	}
   144  
   145  	ginkgo.By("Waiting for all pods to be running")
   146  	for _, config := range configs {
   147  		err = e2epod.WaitForPodRunningInNamespace(ctx, c, config.pod)
   148  		framework.ExpectNoError(err)
   149  	}
   150  }