Adding fsGroup check before mounting a volume

fsGroup check will be enforcing that if a volume has already been
mounted by one pod and another pod wants to mount it but has a different
fsGroup value, this mount operation will not be allowed.
This commit is contained in:
Serguei Bezverkhi
2017-08-01 10:05:59 -04:00
parent 05e7f6d073
commit 1be99dd78e
6 changed files with 202 additions and 13 deletions

View File

@@ -18,13 +18,17 @@ package local
import (
"fmt"
"os"
"github.com/golang/glog"
"os"
"syscall"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/pkg/util/keymutex"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
@@ -38,7 +42,9 @@ func ProbeVolumePlugins() []volume.VolumePlugin {
}
type localVolumePlugin struct {
host volume.VolumeHost
host volume.VolumeHost
volumeLocks keymutex.KeyMutex
recorder record.EventRecorder
}
var _ volume.VolumePlugin = &localVolumePlugin{}
@@ -50,6 +56,11 @@ const (
func (plugin *localVolumePlugin) Init(host volume.VolumeHost) error {
plugin.host = host
plugin.volumeLocks = keymutex.NewKeyMutex()
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof)
recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "localvolume"})
plugin.recorder = recorder
return nil
}
@@ -102,6 +113,7 @@ func (plugin *localVolumePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ vo
return &localVolumeMounter{
localVolume: &localVolume{
pod: pod,
podUID: pod.UID,
volName: spec.Name(),
mounter: plugin.host.GetMounter(plugin.GetPluginName()),
@@ -146,6 +158,7 @@ func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath strin
// The directory at the globalPath will be bind-mounted to the pod's directory
type localVolume struct {
volName string
pod *v1.Pod
podUID types.UID
// Global path to the volume
globalPath string
@@ -188,6 +201,9 @@ func (m *localVolumeMounter) SetUp(fsGroup *int64) error {
// SetUpAt bind mounts the directory to the volume path and sets up volume ownership
func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
m.plugin.volumeLocks.LockKey(m.globalPath)
defer m.plugin.volumeLocks.UnlockKey(m.globalPath)
if m.globalPath == "" {
err := fmt.Errorf("LocalVolume volume %q path is empty", m.volName)
return err
@@ -204,9 +220,30 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
glog.Errorf("cannot validate mount point: %s %v", dir, err)
return err
}
if !notMnt {
return nil
}
refs, err := mount.GetMountRefsByDev(m.mounter, m.globalPath)
if fsGroup != nil {
if err != nil {
glog.Errorf("cannot collect mounting information: %s %v", m.globalPath, err)
return err
}
if len(refs) > 0 {
fsGroupNew := int64(*fsGroup)
fsGroupSame, fsGroupOld, err := isSameFSGroup(m.globalPath, fsGroupNew)
if err != nil {
err = fmt.Errorf("failed to check fsGroup for %s (%v)", m.globalPath, err)
return err
}
if !fsGroupSame {
m.plugin.recorder.Eventf(m.pod, v1.EventTypeWarning, events.WarnAlreadyMountedVolume, "The requested fsGroup is %d, but the volume %s has GID %d. The volume may not be shareable.", fsGroupNew, m.volName, fsGroupOld)
}
}
}
if err := os.MkdirAll(dir, 0750); err != nil {
glog.Errorf("mkdir failed on disk %s (%v)", dir, err)
@@ -247,14 +284,29 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
os.Remove(dir)
return err
}
if !m.readOnly {
// TODO: how to prevent multiple mounts with conflicting fsGroup?
return volume.SetVolumeOwnership(m, fsGroup)
// Volume owner will be written only once on the first volume mount
if len(refs) == 0 {
return volume.SetVolumeOwnership(m, fsGroup)
}
}
return nil
}
// isSameFSGroup is called only for requests to mount an already mounted
// volume. It checks if fsGroup of new mount request is the same or not.
// It returns false if it not the same. It also returns current Gid of a path
// provided for dir variable.
func isSameFSGroup(dir string, fsGroup int64) (bool, int, error) {
info, err := os.Stat(dir)
if err != nil {
glog.Errorf("Error getting stats for %s (%v)", dir, err)
return false, 0, err
}
s := info.Sys().(*syscall.Stat_t)
return int(s.Gid) == int(fsGroup), int(s.Gid), nil
}
type localVolumeUnmounter struct {
*localVolume
}