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

     1  /*
     2  Copyright 2022 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 csimock
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	"github.com/onsi/ginkgo/v2"
    25  	"github.com/onsi/gomega"
    26  
    27  	v1 "k8s.io/api/core/v1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/fields"
    31  	"k8s.io/kubernetes/pkg/kubelet/events"
    32  	"k8s.io/kubernetes/test/e2e/framework"
    33  	e2eevents "k8s.io/kubernetes/test/e2e/framework/events"
    34  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    35  	e2evolume "k8s.io/kubernetes/test/e2e/framework/volume"
    36  	storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
    37  	"k8s.io/kubernetes/test/e2e/storage/utils"
    38  	admissionapi "k8s.io/pod-security-admission/api"
    39  )
    40  
    41  var _ = utils.SIGDescribe("CSI Mock volume attach", func() {
    42  	// The CSIDriverRegistry feature gate is needed for this test in Kubernetes 1.12.
    43  	f := framework.NewDefaultFramework("csi-mock-volumes-attach")
    44  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    45  	m := newMockDriverSetup(f)
    46  
    47  	ginkgo.Context("CSI attach test using mock driver", func() {
    48  		tests := []struct {
    49  			name                   string
    50  			disableAttach          bool
    51  			deployClusterRegistrar bool
    52  			volumeType             volumeType
    53  		}{
    54  			{
    55  				name:                   "should not require VolumeAttach for drivers without attachment",
    56  				disableAttach:          true,
    57  				deployClusterRegistrar: true,
    58  			},
    59  			{
    60  				name:                   "should require VolumeAttach for drivers with attachment",
    61  				deployClusterRegistrar: true,
    62  			},
    63  			{
    64  				name:                   "should require VolumeAttach for ephemermal volume and drivers with attachment",
    65  				deployClusterRegistrar: true,
    66  				volumeType:             genericEphemeral,
    67  			},
    68  			{
    69  				name:                   "should preserve attachment policy when no CSIDriver present",
    70  				deployClusterRegistrar: false,
    71  			},
    72  		}
    73  		for _, t := range tests {
    74  			test := t
    75  			ginkgo.It(t.name, func(ctx context.Context) {
    76  				var err error
    77  				m.init(ctx, testParameters{registerDriver: test.deployClusterRegistrar, disableAttach: test.disableAttach})
    78  				ginkgo.DeferCleanup(m.cleanup)
    79  
    80  				volumeType := test.volumeType
    81  				if volumeType == "" {
    82  					volumeType = pvcReference
    83  				}
    84  				_, claim, pod := m.createPod(ctx, volumeType)
    85  				if pod == nil {
    86  					return
    87  				}
    88  				err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod.Name, pod.Namespace)
    89  				framework.ExpectNoError(err, "Failed to start pod: %v", err)
    90  
    91  				ginkgo.By("Checking if VolumeAttachment was created for the pod")
    92  				testConfig := storageframework.ConvertTestConfig(m.config)
    93  				attachmentName := e2evolume.GetVolumeAttachmentName(ctx, m.cs, testConfig, m.provisioner, claim.Name, claim.Namespace)
    94  				_, err = m.cs.StorageV1().VolumeAttachments().Get(context.TODO(), attachmentName, metav1.GetOptions{})
    95  				if err != nil {
    96  					if apierrors.IsNotFound(err) {
    97  						if !test.disableAttach {
    98  							framework.ExpectNoError(err, "Expected VolumeAttachment but none was found")
    99  						}
   100  					} else {
   101  						framework.ExpectNoError(err, "Failed to find VolumeAttachment")
   102  					}
   103  				}
   104  				if test.disableAttach {
   105  					gomega.Expect(err).To(gomega.MatchError(apierrors.IsNotFound, "Unexpected VolumeAttachment found"))
   106  				}
   107  			})
   108  
   109  		}
   110  	})
   111  
   112  	ginkgo.Context("CSI CSIDriver deployment after pod creation using non-attachable mock driver", func() {
   113  		f.It("should bringup pod after deploying CSIDriver attach=false", f.WithSlow(), func(ctx context.Context) {
   114  			var err error
   115  			m.init(ctx, testParameters{registerDriver: false, disableAttach: true})
   116  			ginkgo.DeferCleanup(m.cleanup)
   117  
   118  			_, claim, pod := m.createPod(ctx, pvcReference) // late binding as specified above
   119  			if pod == nil {
   120  				return
   121  			}
   122  
   123  			ginkgo.By("Checking if attaching failed and pod cannot start")
   124  			eventSelector := fields.Set{
   125  				"involvedObject.kind":      "Pod",
   126  				"involvedObject.name":      pod.Name,
   127  				"involvedObject.namespace": pod.Namespace,
   128  				"reason":                   events.FailedAttachVolume,
   129  			}.AsSelector().String()
   130  			msg := "AttachVolume.Attach failed for volume"
   131  
   132  			err = e2eevents.WaitTimeoutForEvent(ctx, m.cs, pod.Namespace, eventSelector, msg, f.Timeouts.PodStart)
   133  			if err != nil {
   134  				getPod := e2epod.Get(m.cs, pod)
   135  				gomega.Consistently(ctx, getPod).WithTimeout(10*time.Second).Should(e2epod.BeInPhase(v1.PodPending),
   136  					"Pod should not be in running status because attaching should failed")
   137  				// Events are unreliable, don't depend on the event. It's used only to speed up the test.
   138  				framework.Logf("Attach should fail and the corresponding event should show up, error: %v", err)
   139  			}
   140  
   141  			// VolumeAttachment should be created because the default value for CSI attachable is true
   142  			ginkgo.By("Checking if VolumeAttachment was created for the pod")
   143  			testConfig := storageframework.ConvertTestConfig(m.config)
   144  			attachmentName := e2evolume.GetVolumeAttachmentName(ctx, m.cs, testConfig, m.provisioner, claim.Name, claim.Namespace)
   145  			_, err = m.cs.StorageV1().VolumeAttachments().Get(context.TODO(), attachmentName, metav1.GetOptions{})
   146  			if err != nil {
   147  				if apierrors.IsNotFound(err) {
   148  					framework.ExpectNoError(err, "Expected VolumeAttachment but none was found")
   149  				} else {
   150  					framework.ExpectNoError(err, "Failed to find VolumeAttachment")
   151  				}
   152  			}
   153  
   154  			ginkgo.By("Deploy CSIDriver object with attachRequired=false")
   155  			driverNamespace := m.config.DriverNamespace
   156  
   157  			canAttach := false
   158  			o := utils.PatchCSIOptions{
   159  				OldDriverName: "csi-mock",
   160  				NewDriverName: "csi-mock-" + f.UniqueName,
   161  				CanAttach:     &canAttach,
   162  			}
   163  			err = utils.CreateFromManifests(ctx, f, driverNamespace, func(item interface{}) error {
   164  				return utils.PatchCSIDeployment(f, o, item)
   165  			}, "test/e2e/testing-manifests/storage-csi/mock/csi-mock-driverinfo.yaml")
   166  			if err != nil {
   167  				framework.Failf("fail to deploy CSIDriver object: %v", err)
   168  			}
   169  
   170  			ginkgo.By("Wait for the pod in running status")
   171  			err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod.Name, pod.Namespace)
   172  			framework.ExpectNoError(err, "Failed to start pod: %v", err)
   173  
   174  			ginkgo.By(fmt.Sprintf("Wait for the volumeattachment to be deleted up to %v", csiVolumeAttachmentTimeout))
   175  			// This step can be slow because we have to wait either a NodeUpdate event happens or
   176  			// the detachment for this volume timeout so that we can do a force detach.
   177  			err = e2evolume.WaitForVolumeAttachmentTerminated(ctx, attachmentName, m.cs, csiVolumeAttachmentTimeout)
   178  			framework.ExpectNoError(err, "Failed to delete VolumeAttachment: %v", err)
   179  		})
   180  	})
   181  })