Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What happened: During I develop a driver that supports raw block devices but do not need to be attached to nodes, I found it would fail when a pod mount a raw block device. PS: I use cluster-driver register and make requiredAttach as false. kubectl get csidriver csi-xxx -o yaml ! What you expected to happen: Mount a raw block device successfully. How to reproduce it (as minimally and precisely as possible): driver that supports raw block devices but do not need to be attached to nodes, I found it would fail when a pod mount a raw block device. cluster-driver register and make requiredAttach as false. a pod with raw block devices Anything else we need to know?: Environment: Kubernetes version (use ): 1.15 Cloud provider or hardware configuration: BaiduCloud OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others:
/sig storage /assign
I would send a PR later

Discussion:
klog.Infof(log("blockMapper.stageVolumeForBlock STAGE_UNSTAGE_VOLUME capability not set. Skipping MountDevice...")) return "", nil } <del> publishVolumeInfo := attachment.Status.AttachmentMetadata </del> <ins> publishVolumeInfo := map[string]string{} if attachment != nil { publishVolumeInfo = attachment.Status.AttachmentMetadata } </ins> nodeStageSecrets := map[string]string{} if csiSource.NodeStageSecretRef != nil { nodeStageSecrets, err = getCredentialsFromSecret(m.k8s, csiSource.NodeStageSecretRef)

) (string, error) { klog.V(4).Infof(log("blockMapper.publishVolumeForBlock called")) <del> publishVolumeInfo := attachment.Status.AttachmentMetadata </del> <ins> publishVolumeInfo := map[string]string{} if attachment != nil { publishVolumeInfo = attachment.Status.AttachmentMetadata } </ins> nodePublishSecrets := map[string]string{} var err error

return "", err } <del> // Search for attachment by VolumeAttachment.Spec.Source.PersistentVolumeName nodeName := string(m.plugin.host.GetNodeName()) attachID := getAttachmentName(csiSource.VolumeHandle, csiSource.Driver, nodeName) attachment, err := m.k8s.StorageV1().VolumeAttachments().Get(attachID, meta.GetOptions{}) </del> <ins> driverName := csiSource.Driver skip, err := m.plugin.skipAttach(driverName) </ins> if err != nil { <del> klog.Error(log("blockMapper.SetupDevice failed to get volume attachment [id=%v]: %v", attachID, err)) </del> <ins> klog.Error(log("blockMapper.SetupDevice failed to check CSIDriver for %s: %v", driverName, err)) </ins> return "", err } <del> if attachment == nil { klog.Error(log("blockMapper.SetupDevice unable to find VolumeAttachment [id=%s]", attachID)) return "", errors.New("no existing VolumeAttachment found") </del> <ins> var attachment *storage.VolumeAttachment if !skip { // Search for attachment by VolumeAttachment.Spec.Source.PersistentVolumeName nodeName := string(m.plugin.host.GetNodeName()) attachID := getAttachmentName(csiSource.VolumeHandle, csiSource.Driver, nodeName) attachment, err = m.k8s.StorageV1().VolumeAttachments().Get(attachID, meta.GetOptions{}) if err != nil { klog.Error(log("blockMapper.SetupDevice failed to get volume attachment [id=%v]: %v", attachID, err)) return "", err } </ins> } //TODO (vladimirvivien) implement better AccessModes mapping between k8s and CSI

"testing" api "k8s.io/api/core/v1" <ins> "k8s.io/api/storage/v1beta1" </ins> meta "k8s.io/apimachinery/pkg/apis/meta/v1" utilfeature "k8s.io/apiserver/pkg/util/feature" fakeclient "k8s.io/client-go/kubernetes/fake"

} } <ins> func TestBlockMapperMapDeviceNotSupportAttach(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIDriverRegistry, true)() plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) fakeClient := fakeclient.NewSimpleClientset() attachRequired := false fakeDriver := &v1beta1.CSIDriver{ ObjectMeta: meta.ObjectMeta{ Name: testDriver, }, Spec: v1beta1.CSIDriverSpec{ AttachRequired: &attachRequired, }, } _, err := plug.host.GetKubeClient().StorageV1beta1().CSIDrivers().Create(fakeDriver) if err != nil { t.Fatalf("Failed to create a fakeDriver: %v", err) } host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, fakeClient, nil, "fakeNode", nil, ) plug.host = host csiMapper, _, _, err := prepareBlockMapperTest(plug, "test-pv", t) if err != nil { t.Fatalf("Failed to make a new Mapper: %v", err) } csiMapper.csiClient = setupClient(t, true) devicePath, err := csiMapper.SetUpDevice() if err != nil { t.Fatalf("mapper failed to SetupDevice: %v", err) } globalMapPath, err := csiMapper.GetGlobalMapPath(csiMapper.spec) if err != nil { t.Fatalf("mapper failed to GetGlobalMapPath: %v", err) } // Actual SetupDevice should create a symlink to or a bind mout of device in devicePath. // Create dummy file there before calling MapDevice to test it properly. fd, err := os.Create(devicePath) if err != nil { t.Fatalf("mapper failed to create dummy file in devicePath: %v", err) } if err := fd.Close(); err != nil { t.Fatalf("mapper failed to close dummy file in devicePath: %v", err) } // Map device to global and pod device map path volumeMapPath, volName := csiMapper.GetPodDeviceMapPath() err = csiMapper.MapDevice(devicePath, globalMapPath, volumeMapPath, volName, csiMapper.podUID) if err != nil { t.Fatalf("mapper failed to GetGlobalMapPath: %v", err) } // Check if symlink {globalMapPath}/{podUID} exists globalMapFilePath := filepath.Join(globalMapPath, string(csiMapper.podUID)) if _, err := os.Stat(globalMapFilePath); err != nil { if os.IsNotExist(err) { t.Errorf("mapper.MapDevice failed, symlink in globalMapPath not created: %v", err) t.Errorf("mapper.MapDevice devicePath:%v, globalMapPath: %v, globalMapFilePath: %v", devicePath, globalMapPath, globalMapFilePath) } else { t.Errorf("mapper.MapDevice failed: %v", err) } } // Check if symlink {volumeMapPath}/{volName} exists volumeMapFilePath := filepath.Join(volumeMapPath, volName) if _, err := os.Stat(volumeMapFilePath); err != nil { if os.IsNotExist(err) { t.Errorf("mapper.MapDevice failed, symlink in volumeMapPath not created: %v", err) } else { t.Errorf("mapper.MapDevice failed: %v", err) } } } </ins> func TestBlockMapperTearDownDevice(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()