mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
attacher/detacher refactor
This commit is contained in:
parent
05acb32aca
commit
c7e4466873
@ -150,6 +150,10 @@ type volumeToMount struct {
|
|||||||
// the volume.Attacher interface
|
// the volume.Attacher interface
|
||||||
pluginIsAttachable bool
|
pluginIsAttachable bool
|
||||||
|
|
||||||
|
// pluginIsDeviceMountable indicates that the plugin for this volume implements
|
||||||
|
// the volume.DeviceMounter interface
|
||||||
|
pluginIsDeviceMountable bool
|
||||||
|
|
||||||
// volumeGidValue contains the value of the GID annotation, if present.
|
// volumeGidValue contains the value of the GID annotation, if present.
|
||||||
volumeGidValue string
|
volumeGidValue string
|
||||||
|
|
||||||
@ -220,13 +224,16 @@ func (dsw *desiredStateOfWorld) AddPodToVolume(
|
|||||||
volumeName = util.GetUniqueVolumeNameForNonAttachableVolume(podName, volumePlugin, volumeSpec)
|
volumeName = util.GetUniqueVolumeNameForNonAttachableVolume(podName, volumePlugin, volumeSpec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceMountable := dsw.isDeviceMountableVolume(volumeSpec)
|
||||||
|
|
||||||
if _, volumeExists := dsw.volumesToMount[volumeName]; !volumeExists {
|
if _, volumeExists := dsw.volumesToMount[volumeName]; !volumeExists {
|
||||||
dsw.volumesToMount[volumeName] = volumeToMount{
|
dsw.volumesToMount[volumeName] = volumeToMount{
|
||||||
volumeName: volumeName,
|
volumeName: volumeName,
|
||||||
podsToMount: make(map[types.UniquePodName]podToMount),
|
podsToMount: make(map[types.UniquePodName]podToMount),
|
||||||
pluginIsAttachable: attachable,
|
pluginIsAttachable: attachable,
|
||||||
volumeGidValue: volumeGidValue,
|
pluginIsDeviceMountable: deviceMountable,
|
||||||
reportedInUse: false,
|
volumeGidValue: volumeGidValue,
|
||||||
|
reportedInUse: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,14 +353,15 @@ func (dsw *desiredStateOfWorld) GetVolumesToMount() []VolumeToMount {
|
|||||||
volumesToMount,
|
volumesToMount,
|
||||||
VolumeToMount{
|
VolumeToMount{
|
||||||
VolumeToMount: operationexecutor.VolumeToMount{
|
VolumeToMount: operationexecutor.VolumeToMount{
|
||||||
VolumeName: volumeName,
|
VolumeName: volumeName,
|
||||||
PodName: podName,
|
PodName: podName,
|
||||||
Pod: podObj.pod,
|
Pod: podObj.pod,
|
||||||
VolumeSpec: podObj.volumeSpec,
|
VolumeSpec: podObj.volumeSpec,
|
||||||
PluginIsAttachable: volumeObj.pluginIsAttachable,
|
PluginIsAttachable: volumeObj.pluginIsAttachable,
|
||||||
OuterVolumeSpecName: podObj.outerVolumeSpecName,
|
PluginIsDeviceMountable: volumeObj.pluginIsDeviceMountable,
|
||||||
VolumeGidValue: volumeObj.volumeGidValue,
|
OuterVolumeSpecName: podObj.outerVolumeSpecName,
|
||||||
ReportedInUse: volumeObj.reportedInUse}})
|
VolumeGidValue: volumeObj.volumeGidValue,
|
||||||
|
ReportedInUse: volumeObj.reportedInUse}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return volumesToMount
|
return volumesToMount
|
||||||
@ -371,3 +379,15 @@ func (dsw *desiredStateOfWorld) isAttachableVolume(volumeSpec *volume.Spec) bool
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dsw *desiredStateOfWorld) isDeviceMountableVolume(volumeSpec *volume.Spec) bool {
|
||||||
|
deviceMountableVolumePlugin, _ := dsw.volumePluginMgr.FindDeviceMountablePluginBySpec(volumeSpec)
|
||||||
|
if deviceMountableVolumePlugin != nil {
|
||||||
|
volumeDeviceMounter, err := deviceMountableVolumePlugin.NewDeviceMounter()
|
||||||
|
if err == nil && volumeDeviceMounter != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -202,9 +202,17 @@ type ProvisionableVolumePlugin interface {
|
|||||||
// AttachableVolumePlugin is an extended interface of VolumePlugin and is used for volumes that require attachment
|
// AttachableVolumePlugin is an extended interface of VolumePlugin and is used for volumes that require attachment
|
||||||
// to a node before mounting.
|
// to a node before mounting.
|
||||||
type AttachableVolumePlugin interface {
|
type AttachableVolumePlugin interface {
|
||||||
VolumePlugin
|
DeviceMountableVolumePlugin
|
||||||
NewAttacher() (Attacher, error)
|
NewAttacher() (Attacher, error)
|
||||||
NewDetacher() (Detacher, error)
|
NewDetacher() (Detacher, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceMountableVolumePlugin is an extended interface of VolumePlugin and is used
|
||||||
|
// for volumes that requires mount device to a node before binding to volume to pod.
|
||||||
|
type DeviceMountableVolumePlugin interface {
|
||||||
|
VolumePlugin
|
||||||
|
NewDeviceMounter() (DeviceMounter, error)
|
||||||
|
NewDeviceUnmounter() (DeviceUnmounter, error)
|
||||||
GetDeviceMountRefs(deviceMountPath string) ([]string, error)
|
GetDeviceMountRefs(deviceMountPath string) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,6 +765,30 @@ func (pm *VolumePluginMgr) FindAttachablePluginByName(name string) (AttachableVo
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindDeviceMountablePluginBySpec fetches a persistent volume plugin by spec.
|
||||||
|
func (pm *VolumePluginMgr) FindDeviceMountablePluginBySpec(spec *Spec) (DeviceMountableVolumePlugin, error) {
|
||||||
|
volumePlugin, err := pm.FindPluginBySpec(spec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if deviceMountableVolumePlugin, ok := volumePlugin.(DeviceMountableVolumePlugin); ok {
|
||||||
|
return deviceMountableVolumePlugin, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindDeviceMountablePluginByName fetches a devicemountable volume plugin by name.
|
||||||
|
func (pm *VolumePluginMgr) FindDeviceMountablePluginByName(name string) (DeviceMountableVolumePlugin, error) {
|
||||||
|
volumePlugin, err := pm.FindPluginByName(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if deviceMountableVolumePlugin, ok := volumePlugin.(DeviceMountableVolumePlugin); ok {
|
||||||
|
return deviceMountableVolumePlugin, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindExpandablePluginBySpec fetches a persistent volume plugin by spec.
|
// FindExpandablePluginBySpec fetches a persistent volume plugin by spec.
|
||||||
func (pm *VolumePluginMgr) FindExpandablePluginBySpec(spec *Spec) (ExpandableVolumePlugin, error) {
|
func (pm *VolumePluginMgr) FindExpandablePluginBySpec(spec *Spec) (ExpandableVolumePlugin, error) {
|
||||||
volumePlugin, err := pm.FindPluginBySpec(spec)
|
volumePlugin, err := pm.FindPluginBySpec(spec)
|
||||||
|
@ -329,6 +329,10 @@ type VolumeToMount struct {
|
|||||||
// the volume.Attacher interface
|
// the volume.Attacher interface
|
||||||
PluginIsAttachable bool
|
PluginIsAttachable bool
|
||||||
|
|
||||||
|
// PluginIsDeviceMountable indicates that the plugin for this volume implements
|
||||||
|
// the volume.DeviceMounter interface
|
||||||
|
PluginIsDeviceMountable bool
|
||||||
|
|
||||||
// VolumeGidValue contains the value of the GID annotation, if present.
|
// VolumeGidValue contains the value of the GID annotation, if present.
|
||||||
VolumeGidValue string
|
VolumeGidValue string
|
||||||
|
|
||||||
@ -738,8 +742,8 @@ func (oe *operationExecutor) MountVolume(
|
|||||||
podName := nestedpendingoperations.EmptyUniquePodName
|
podName := nestedpendingoperations.EmptyUniquePodName
|
||||||
|
|
||||||
// TODO: remove this -- not necessary
|
// TODO: remove this -- not necessary
|
||||||
if !volumeToMount.PluginIsAttachable {
|
if !volumeToMount.PluginIsAttachable && !volumeToMount.PluginIsDeviceMountable {
|
||||||
// Non-attachable volume plugins can execute mount for multiple pods
|
// volume plugins which are Non-attachable and Non-deviceMountable can execute mount for multiple pods
|
||||||
// referencing the same volume in parallel
|
// referencing the same volume in parallel
|
||||||
podName = util.GetUniquePodName(volumeToMount.Pod)
|
podName = util.GetUniquePodName(volumeToMount.Pod)
|
||||||
}
|
}
|
||||||
|
@ -478,6 +478,13 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
|||||||
volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
|
volumeAttacher, _ = attachableVolumePlugin.NewAttacher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get deviceMounter, if possible
|
||||||
|
deviceMountableVolumePlugin, _ := og.volumePluginMgr.FindDeviceMountablePluginBySpec(volumeToMount.VolumeSpec)
|
||||||
|
var volumeDeviceMounter volume.DeviceMounter
|
||||||
|
if deviceMountableVolumePlugin != nil {
|
||||||
|
volumeDeviceMounter, _ = deviceMountableVolumePlugin.NewDeviceMounter()
|
||||||
|
}
|
||||||
|
|
||||||
var fsGroup *int64
|
var fsGroup *int64
|
||||||
if volumeToMount.Pod.Spec.SecurityContext != nil &&
|
if volumeToMount.Pod.Spec.SecurityContext != nil &&
|
||||||
volumeToMount.Pod.Spec.SecurityContext.FSGroup != nil {
|
volumeToMount.Pod.Spec.SecurityContext.FSGroup != nil {
|
||||||
@ -485,28 +492,31 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mountVolumeFunc := func() (error, error) {
|
mountVolumeFunc := func() (error, error) {
|
||||||
|
devicePath := volumeToMount.DevicePath
|
||||||
if volumeAttacher != nil {
|
if volumeAttacher != nil {
|
||||||
// Wait for attachable volumes to finish attaching
|
// Wait for attachable volumes to finish attaching
|
||||||
glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)))
|
glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach entering", fmt.Sprintf("DevicePath %q", volumeToMount.DevicePath)))
|
||||||
|
|
||||||
devicePath, err := volumeAttacher.WaitForAttach(
|
devicePath, err = volumeAttacher.WaitForAttach(
|
||||||
volumeToMount.VolumeSpec, volumeToMount.DevicePath, volumeToMount.Pod, waitForAttachTimeout)
|
volumeToMount.VolumeSpec, devicePath, volumeToMount.Pod, waitForAttachTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// On failure, return error. Caller will log and retry.
|
// On failure, return error. Caller will log and retry.
|
||||||
return volumeToMount.GenerateError("MountVolume.WaitForAttach failed", err)
|
return volumeToMount.GenerateError("MountVolume.WaitForAttach failed", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)))
|
glog.Infof(volumeToMount.GenerateMsgDetailed("MountVolume.WaitForAttach succeeded", fmt.Sprintf("DevicePath %q", devicePath)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if volumeDeviceMounter != nil {
|
||||||
deviceMountPath, err :=
|
deviceMountPath, err :=
|
||||||
volumeAttacher.GetDeviceMountPath(volumeToMount.VolumeSpec)
|
volumeDeviceMounter.GetDeviceMountPath(volumeToMount.VolumeSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// On failure, return error. Caller will log and retry.
|
// On failure, return error. Caller will log and retry.
|
||||||
return volumeToMount.GenerateError("MountVolume.GetDeviceMountPath failed", err)
|
return volumeToMount.GenerateError("MountVolume.GetDeviceMountPath failed", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount device to global mount path
|
// Mount device to global mount path
|
||||||
err = volumeAttacher.MountDevice(
|
err = volumeDeviceMounter.MountDevice(
|
||||||
volumeToMount.VolumeSpec,
|
volumeToMount.VolumeSpec,
|
||||||
devicePath,
|
devicePath,
|
||||||
deviceMountPath)
|
deviceMountPath)
|
||||||
@ -532,7 +542,6 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
|||||||
if resizeSimpleError != nil || resizeDetailedError != nil {
|
if resizeSimpleError != nil || resizeDetailedError != nil {
|
||||||
return resizeSimpleError, resizeDetailedError
|
return resizeSimpleError, resizeDetailedError
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if og.checkNodeCapabilitiesBeforeMount {
|
if og.checkNodeCapabilitiesBeforeMount {
|
||||||
@ -718,20 +727,31 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
|||||||
deviceToDetach AttachedVolume,
|
deviceToDetach AttachedVolume,
|
||||||
actualStateOfWorld ActualStateOfWorldMounterUpdater,
|
actualStateOfWorld ActualStateOfWorldMounterUpdater,
|
||||||
mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
mounter mount.Interface) (volumetypes.GeneratedOperations, error) {
|
||||||
// Get attacher plugin
|
// Get DeviceMounter plugin
|
||||||
attachableVolumePlugin, err :=
|
deviceMountableVolumePlugin, err :=
|
||||||
og.volumePluginMgr.FindAttachablePluginByName(deviceToDetach.PluginName)
|
og.volumePluginMgr.FindDeviceMountablePluginByName(deviceToDetach.PluginName)
|
||||||
if err != nil || attachableVolumePlugin == nil {
|
if err != nil || deviceMountableVolumePlugin == nil {
|
||||||
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindAttachablePluginBySpec failed", err)
|
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindDeviceMountablePluginByName failed", err)
|
||||||
|
}
|
||||||
|
volumeDeviceUmounter, err := deviceMountableVolumePlugin.NewDeviceUnmounter()
|
||||||
|
if err != nil {
|
||||||
|
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceUmounter failed", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeDetacher, err := attachableVolumePlugin.NewDetacher()
|
volumeDeviceMounter, err := deviceMountableVolumePlugin.NewDeviceMounter()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDetacher failed", err)
|
return volumetypes.GeneratedOperations{}, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDeviceMounter failed", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
unmountDeviceFunc := func() (error, error) {
|
unmountDeviceFunc := func() (error, error) {
|
||||||
deviceMountPath := deviceToDetach.DeviceMountPath
|
//deviceMountPath := deviceToDetach.DeviceMountPath
|
||||||
refs, err := attachableVolumePlugin.GetDeviceMountRefs(deviceMountPath)
|
deviceMountPath, err :=
|
||||||
|
volumeDeviceMounter.GetDeviceMountPath(deviceToDetach.VolumeSpec)
|
||||||
|
if err != nil {
|
||||||
|
// On failure, return error. Caller will log and retry.
|
||||||
|
return deviceToDetach.GenerateError("GetDeviceMountPath failed", err)
|
||||||
|
}
|
||||||
|
refs, err := deviceMountableVolumePlugin.GetDeviceMountRefs(deviceMountPath)
|
||||||
|
|
||||||
if err != nil || mount.HasMountRefs(deviceMountPath, refs) {
|
if err != nil || mount.HasMountRefs(deviceMountPath, refs) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -740,7 +760,7 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
|||||||
return deviceToDetach.GenerateError("GetDeviceMountRefs check failed", err)
|
return deviceToDetach.GenerateError("GetDeviceMountRefs check failed", err)
|
||||||
}
|
}
|
||||||
// Execute unmount
|
// Execute unmount
|
||||||
unmountDeviceErr := volumeDetacher.UnmountDevice(deviceMountPath)
|
unmountDeviceErr := volumeDeviceUmounter.UnmountDevice(deviceMountPath)
|
||||||
if unmountDeviceErr != nil {
|
if unmountDeviceErr != nil {
|
||||||
// On failure, return error. Caller will log and retry.
|
// On failure, return error. Caller will log and retry.
|
||||||
return deviceToDetach.GenerateError("UnmountDevice failed", unmountDeviceErr)
|
return deviceToDetach.GenerateError("UnmountDevice failed", unmountDeviceErr)
|
||||||
@ -775,7 +795,7 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
|
|||||||
|
|
||||||
return volumetypes.GeneratedOperations{
|
return volumetypes.GeneratedOperations{
|
||||||
OperationFunc: unmountDeviceFunc,
|
OperationFunc: unmountDeviceFunc,
|
||||||
CompleteFunc: util.OperationCompleteHook(attachableVolumePlugin.GetPluginName(), "unmount_device"),
|
CompleteFunc: util.OperationCompleteHook(deviceMountableVolumePlugin.GetPluginName(), "unmount_device"),
|
||||||
EventRecorderFunc: nil, // nil because we do not want to generate event on error
|
EventRecorderFunc: nil, // nil because we do not want to generate event on error
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,8 @@ type Deleter interface {
|
|||||||
|
|
||||||
// Attacher can attach a volume to a node.
|
// Attacher can attach a volume to a node.
|
||||||
type Attacher interface {
|
type Attacher interface {
|
||||||
|
DeviceMounter
|
||||||
|
|
||||||
// Attaches the volume specified by the given spec to the node with the given Name.
|
// Attaches the volume specified by the given spec to the node with the given Name.
|
||||||
// On success, returns the device path where the device was attached on the
|
// On success, returns the device path where the device was attached on the
|
||||||
// node.
|
// node.
|
||||||
@ -219,7 +221,10 @@ type Attacher interface {
|
|||||||
// is returned. Otherwise, if the device does not attach after
|
// is returned. Otherwise, if the device does not attach after
|
||||||
// the given timeout period, an error will be returned.
|
// the given timeout period, an error will be returned.
|
||||||
WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error)
|
WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod, timeout time.Duration) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceMounter can mount a block volume to a global path.
|
||||||
|
type DeviceMounter interface {
|
||||||
// GetDeviceMountPath returns a path where the device should
|
// GetDeviceMountPath returns a path where the device should
|
||||||
// be mounted after it is attached. This is a global mount
|
// be mounted after it is attached. This is a global mount
|
||||||
// point which should be bind mounted for individual volumes.
|
// point which should be bind mounted for individual volumes.
|
||||||
@ -227,6 +232,7 @@ type Attacher interface {
|
|||||||
|
|
||||||
// MountDevice mounts the disk to a global path which
|
// MountDevice mounts the disk to a global path which
|
||||||
// individual pods can then bind mount
|
// individual pods can then bind mount
|
||||||
|
// Note that devicePath can be empty if the volume plugin does not implement any of Attach and WaitForAttach methods.
|
||||||
MountDevice(spec *Spec, devicePath string, deviceMountPath string) error
|
MountDevice(spec *Spec, devicePath string, deviceMountPath string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,11 +246,15 @@ type BulkVolumeVerifier interface {
|
|||||||
|
|
||||||
// Detacher can detach a volume from a node.
|
// Detacher can detach a volume from a node.
|
||||||
type Detacher interface {
|
type Detacher interface {
|
||||||
|
DeviceUnmounter
|
||||||
// Detach the given volume from the node with the given Name.
|
// Detach the given volume from the node with the given Name.
|
||||||
// volumeName is name of the volume as returned from plugin's
|
// volumeName is name of the volume as returned from plugin's
|
||||||
// GetVolumeName().
|
// GetVolumeName().
|
||||||
Detach(volumeName string, nodeName types.NodeName) error
|
Detach(volumeName string, nodeName types.NodeName) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceUnmounter can unmount a block volume from the global path.
|
||||||
|
type DeviceUnmounter interface {
|
||||||
// UnmountDevice unmounts the global mount of the disk. This
|
// UnmountDevice unmounts the global mount of the disk. This
|
||||||
// should only be called once all bind mounts have been
|
// should only be called once all bind mounts have been
|
||||||
// unmounted.
|
// unmounted.
|
||||||
|
Loading…
Reference in New Issue
Block a user