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