Refactor of GenerateMapDeviceFunc to delegate Map call to volume plugin.

pull/8/head
Vladimir Vivien 2018-05-21 08:44:17 -04:00
parent 4c13f5fdf5
commit 3569287993
14 changed files with 133 additions and 51 deletions

View File

@ -463,6 +463,11 @@ func (f *stubBlockVolume) GetPodDeviceMapPath() (string, string) {
func (f *stubBlockVolume) SetUpDevice() (string, error) {
return "", nil
}
func (f stubBlockVolume) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return nil
}
func (f *stubBlockVolume) TearDownDevice(mapPath string, devicePath string) error {
return nil
}

View File

@ -509,12 +509,8 @@ func Test_Run_Positive_VolumeAttachAndMap(t *testing.T) {
1 /* expectedAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetGlobalMapPathCallCount(
1 /* expectedGetGlobalMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetPodDeviceMapPathCallCount(
1 /* expectedPodDeviceMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifySetUpDeviceCallCount(
1 /* expectedSetUpDeviceCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetMapDeviceCallCount(
1 /* expectedGetMapDeviceCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroTearDownDeviceCallCount(fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin))
@ -601,12 +597,8 @@ func Test_Run_Positive_BlockVolumeMapControllerAttachEnabled(t *testing.T) {
assert.NoError(t, volumetesting.VerifyZeroAttachCalls(fakePlugin))
assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetGlobalMapPathCallCount(
1 /* expectedGetGlobalMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetPodDeviceMapPathCallCount(
1 /* expectedPodDeviceMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifySetUpDeviceCallCount(
1 /* expectedSetUpCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetMapDeviceCallCount(
1 /* expectedGetMapDeviceCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroTearDownDeviceCallCount(fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin))
@ -692,12 +684,8 @@ func Test_Run_Positive_BlockVolumeAttachMapUnmapDetach(t *testing.T) {
1 /* expectedAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetGlobalMapPathCallCount(
1 /* expectedGetGlobalMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetPodDeviceMapPathCallCount(
1 /* expectedPodDeviceMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifySetUpDeviceCallCount(
1 /* expectedSetUpCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetMapDeviceCallCount(
1 /* expectedGetMapDeviceCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroTearDownDeviceCallCount(fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin))
@ -796,12 +784,8 @@ func Test_Run_Positive_VolumeUnmapControllerAttachEnabled(t *testing.T) {
assert.NoError(t, volumetesting.VerifyZeroAttachCalls(fakePlugin))
assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetGlobalMapPathCallCount(
1 /* expectedGetGlobalMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetPodDeviceMapPathCallCount(
1 /* expectedPodDeviceMapPathCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifySetUpDeviceCallCount(
1 /* expectedSetUpCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyGetMapDeviceCallCount(
1 /* expectedGetMapDeviceCallCount */, fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroTearDownDeviceCallCount(fakePlugin))
assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin))

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
kstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
@ -155,6 +156,10 @@ func (b *awsElasticBlockStoreMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *awsElasticBlockStoreMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
// GetGlobalMapPath returns global map path and error
// path: plugins/kubernetes.io/{PluginName}/volumeDevices/volumeID
// plugins/kubernetes.io/aws-ebs/volumeDevices/vol-XXXXXX

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
kstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
@ -137,6 +138,10 @@ func (b *azureDataDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *azureDataDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
// GetGlobalMapPath returns global map path and error
// path: plugins/kubernetes.io/{PluginName}/volumeDevices/volumeID
// plugins/kubernetes.io/azure-disk/volumeDevices/vol-XXXXXX

View File

@ -443,6 +443,10 @@ func (b *fcDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *fcDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
type fcDiskUnmapper struct {
*fcDisk
deviceUtil util.DeviceUtil

View File

@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/util/mount"
kstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
@ -151,6 +152,10 @@ func (b *gcePersistentDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *gcePersistentDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
// GetGlobalMapPath returns global map path and error
// path: plugins/kubernetes.io/{PluginName}/volumeDevices/pdName
func (pd *gcePersistentDisk) GetGlobalMapPath(spec *volume.Spec) (string, error) {

View File

@ -367,6 +367,10 @@ func (b *iscsiDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (b *iscsiDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return ioutil.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
type iscsiDiskUnmapper struct {
*iscsiDisk
exec mount.Exec

View File

@ -390,6 +390,10 @@ func (m *localVolumeMapper) SetUpDevice() (string, error) {
return globalPath, nil
}
func (m *localVolumeMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return util.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
// localVolumeUnmapper implements the BlockVolumeUnmapper interface for local volumes.
type localVolumeUnmapper struct {
*localVolume

View File

@ -878,6 +878,10 @@ func (rbd *rbdDiskMapper) SetUpDevice() (string, error) {
return "", nil
}
func (rbd *rbdDiskMapper) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error {
return volutil.MapBlockVolume(devicePath, globalMapPath, volumeMapPath, volumeMapName, podUID)
}
func (rbd *rbd) rbdGlobalMapPath(spec *volume.Spec) (string, error) {
mon, err := getVolumeSourceMonitors(spec)
if err != nil {

View File

@ -512,6 +512,7 @@ type FakeVolume struct {
GetDeviceMountPathCallCount int
SetUpDeviceCallCount int
TearDownDeviceCallCount int
MapDeviceCallCount int
GlobalMapPathCallCount int
PodDeviceMapPathCallCount int
}
@ -642,6 +643,21 @@ func (fv *FakeVolume) GetTearDownDeviceCallCount() int {
return fv.TearDownDeviceCallCount
}
// Block volume support
func (fv *FakeVolume) MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, pod types.UID) error {
fv.Lock()
defer fv.Unlock()
fv.MapDeviceCallCount++
return nil
}
// Block volume support
func (fv *FakeVolume) GetMapDeviceCallCount() int {
fv.RLock()
defer fv.RUnlock()
return fv.MapDeviceCallCount
}
func (fv *FakeVolume) Attach(spec *Spec, nodeName types.NodeName) (string, error) {
fv.Lock()
defer fv.Unlock()
@ -1121,6 +1137,24 @@ func VerifyGetPodDeviceMapPathCallCount(
expectedPodDeviceMapPathCallCount)
}
// VerifyGetMapDeviceCallCount ensures that at least one of the Mappers for this
// plugin has the expectedMapDeviceCallCount number of calls. Otherwise it
// returns an error.
func VerifyGetMapDeviceCallCount(
expectedMapDeviceCallCount int,
fakeVolumePlugin *FakeVolumePlugin) error {
for _, mapper := range fakeVolumePlugin.GetBlockVolumeMapper() {
actualCallCount := mapper.GetMapDeviceCallCount()
if actualCallCount >= expectedMapDeviceCallCount {
return nil
}
}
return fmt.Errorf(
"No Mapper have expected MapdDeviceCallCount. Expected: <%v>.",
expectedMapDeviceCallCount)
}
// GetTestVolumePluginMgr creates, initializes, and returns a test volume plugin
// manager and fake volume plugin using a fake volume host.
func GetTestVolumePluginMgr(

View File

@ -60,6 +60,7 @@ go_library(
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util/types:go_default_library",
"//pkg/volume/util/volumepathhandler:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",

View File

@ -856,37 +856,19 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
// On failure, return error. Caller will log and retry.
return volumeToMount.GenerateError("MapVolume.SetUp failed", mapErr)
}
// Update devicePath for none attachable plugin case
// if pluginDevicePath is provided, assume attacher may not provide device
// or attachment flow uses SetupDevice to get device path
if len(pluginDevicePath) != 0 {
devicePath = pluginDevicePath
}
if len(devicePath) == 0 {
if len(pluginDevicePath) != 0 {
devicePath = pluginDevicePath
} else {
return volumeToMount.GenerateError("MapVolume failed", fmt.Errorf("Device path of the volume is empty"))
}
}
// Update actual state of world to reflect volume is globally mounted
markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
volumeToMount.VolumeName, devicePath, globalMapPath)
if markDeviceMappedErr != nil {
// On failure, return error. Caller will log and retry.
return volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
return volumeToMount.GenerateError("MapVolume failed", fmt.Errorf("Device path of the volume is empty"))
}
mapErr = og.blkUtil.MapDevice(devicePath, globalMapPath, string(volumeToMount.Pod.UID))
if mapErr != nil {
// On failure, return error. Caller will log and retry.
return volumeToMount.GenerateError("MapVolume.MapDevice failed", mapErr)
}
// Device mapping for global map path succeeded
simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MapVolume.MapDevice succeeded", fmt.Sprintf("globalMapPath %q", globalMapPath))
verbosity := glog.Level(4)
og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
glog.V(verbosity).Infof(detailedMsg)
// Map device to pod device map path under the given pod directory using symbolic link
// Map device to global and pod device map path
volumeMapPath, volName := blockVolumeMapper.GetPodDeviceMapPath()
mapErr = og.blkUtil.MapDevice(devicePath, volumeMapPath, volName)
mapErr = blockVolumeMapper.MapDevice(devicePath, globalMapPath, volumeMapPath, volName, volumeToMount.Pod.UID)
if mapErr != nil {
// On failure, return error. Caller will log and retry.
return volumeToMount.GenerateError("MapVolume.MapDevice failed", mapErr)
@ -901,6 +883,20 @@ func (og *operationGenerator) GenerateMapVolumeFunc(
return volumeToMount.GenerateError("MapVolume.AttachFileDevice failed", err)
}
// Update actual state of world to reflect volume is globally mounted
markDeviceMappedErr := actualStateOfWorld.MarkDeviceAsMounted(
volumeToMount.VolumeName, devicePath, globalMapPath)
if markDeviceMappedErr != nil {
// On failure, return error. Caller will log and retry.
return volumeToMount.GenerateError("MapVolume.MarkDeviceAsMounted failed", markDeviceMappedErr)
}
// Device mapping for global map path succeeded
simpleMsg, detailedMsg := volumeToMount.GenerateMsg("MapVolume.MapDevice succeeded", fmt.Sprintf("globalMapPath %q", globalMapPath))
verbosity := glog.Level(4)
og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeNormal, kevents.SuccessfulMountVolume, simpleMsg)
glog.V(verbosity).Infof(detailedMsg)
// Device mapping for pod device map path succeeded
simpleMsg, detailedMsg = volumeToMount.GenerateMsg("MapVolume.MapDevice succeeded", fmt.Sprintf("volumeMapPath %q", volumeMapPath))
verbosity = glog.Level(1)

View File

@ -50,6 +50,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
utypes "k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume/util/types"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
const (
@ -741,3 +742,30 @@ func MakeAbsolutePath(goos, path string) string {
// Otherwise, add 'c:\'
return "c:\\" + path
}
// MapBlockVolume is a utility function to provide a common way of mounting
// block device path for a specified volume and pod. This function should be
// called by volume plugins that implements volume.BlockVolumeMapper.Map() method.
func MapBlockVolume(
devicePath,
globalMapPath,
podVolumeMapPath,
volumeMapName string,
podUID utypes.UID,
) error {
blkUtil := volumepathhandler.NewBlockVolumePathHandler()
// map devicePath to global node path
mapErr := blkUtil.MapDevice(devicePath, globalMapPath, string(podUID))
if mapErr != nil {
return mapErr
}
// map devicePath to pod volume path
mapErr = blkUtil.MapDevice(devicePath, podVolumeMapPath, volumeMapName)
if mapErr != nil {
return mapErr
}
return nil
}

View File

@ -162,6 +162,9 @@ type BlockVolumeMapper interface {
// at attacher.Attach() and attacher.WaitForAttach().
// This may be called more than once, so implementations must be idempotent.
SetUpDevice() (string, error)
// Map maps the block device path for the specified spec and pod.
MapDevice(devicePath, globalMapPath, volumeMapPath, volumeMapName string, podUID types.UID) error
}
// BlockVolumeUnmapper interface provides methods to cleanup/unmap the volumes.