mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
use GetFileType per mount.Interface to check hostpath type
This commit is contained in:
parent
46b0b3491f
commit
57ead4898b
@ -79,6 +79,22 @@ func (mi *fakeMountInterface) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) GetFileType(pathname string) (mount.FileType, error) {
|
||||
return mount.FileType("fake"), nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) ExistsPath(pathname string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func fakeContainerMgrMountInt() mount.Interface {
|
||||
return &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
|
@ -69,7 +69,6 @@ func (kl *Kubelet) newVolumeMounterFromPlugins(spec *volume.Spec, pod *v1.Pod, o
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't use volume plugins for %s: %v", spec.Name(), err)
|
||||
}
|
||||
opts.Containerized = kl.kubeletConfiguration.Containerized
|
||||
physicalMounter, err := plugin.NewMounter(spec, pod, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to instantiate mounter for volume: %s using plugin: %s with a root cause: %v", spec.Name(), plugin.GetPluginName(), err)
|
||||
|
@ -125,7 +125,7 @@ func (f *FakeMounter) List() ([]MountPoint, error) {
|
||||
}
|
||||
|
||||
func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
return mp.Path == dir
|
||||
}
|
||||
|
||||
func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
@ -175,3 +175,19 @@ func (f *FakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (strin
|
||||
func (f *FakeMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) GetFileType(pathname string) (FileType, error) {
|
||||
return FileType("fake"), nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) ExistsPath(pathname string) bool {
|
||||
return false
|
||||
}
|
||||
|
@ -27,10 +27,17 @@ import (
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
type FileType string
|
||||
|
||||
const (
|
||||
// Default mount command if mounter path is not specified
|
||||
defaultMountCommand = "mount"
|
||||
MountsInGlobalPDPath = "mounts"
|
||||
defaultMountCommand = "mount"
|
||||
MountsInGlobalPDPath = "mounts"
|
||||
FileTypeDirectory FileType = "Directory"
|
||||
FileTypeFile FileType = "File"
|
||||
FileTypeSocket FileType = "Socket"
|
||||
FileTypeCharDev FileType = "CharDevice"
|
||||
FileTypeBlockDev FileType = "BlockDevice"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
@ -70,6 +77,18 @@ type Interface interface {
|
||||
// MakeRShared checks that given path is on a mount with 'rshared' mount
|
||||
// propagation. If not, it bind-mounts the path as rshared.
|
||||
MakeRShared(path string) error
|
||||
// GetFileType checks for file/directory/socket/block/character devices.
|
||||
// Will operate in the host mount namespace if kubelet is running in a container
|
||||
GetFileType(pathname string) (FileType, error)
|
||||
// MakeFile creates an empty file.
|
||||
// Will operate in the host mount namespace if kubelet is running in a container
|
||||
MakeFile(pathname string) error
|
||||
// MakeDir creates a new directory.
|
||||
// Will operate in the host mount namespace if kubelet is running in a container
|
||||
MakeDir(pathname string) error
|
||||
// ExistsPath checks whether the path exists.
|
||||
// Will operate in the host mount namespace if kubelet is running in a container
|
||||
ExistsPath(pathname string) bool
|
||||
}
|
||||
|
||||
// Exec executes command where mount utilities are. This can be either the host,
|
||||
|
@ -252,17 +252,29 @@ func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (mounter *Mounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return pathIsDevice(pathname)
|
||||
pathType, err := mounter.GetFileType(pathname)
|
||||
isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
|
||||
return isDevice, err
|
||||
}
|
||||
|
||||
func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
isDevice, err := pathIsDevice(pathname)
|
||||
var isDevice bool
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
isDevice = false
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return false, fmt.Errorf(
|
||||
"PathIsDevice failed for path %q: %v",
|
||||
pathname,
|
||||
err)
|
||||
}
|
||||
// path refers to a device
|
||||
if finfo.Mode()&os.ModeDevice != 0 {
|
||||
isDevice = true
|
||||
}
|
||||
|
||||
if !isDevice {
|
||||
glog.Errorf("Path %q is not refering to a device.", pathname)
|
||||
return false, nil
|
||||
@ -282,23 +294,6 @@ func exclusiveOpenFailsOnDevice(pathname string) (bool, error) {
|
||||
return false, errno
|
||||
}
|
||||
|
||||
func pathIsDevice(pathname string) (bool, error) {
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// path refers to a device
|
||||
if finfo.Mode()&os.ModeDevice != 0 {
|
||||
return true, nil
|
||||
}
|
||||
// path does not refer to device
|
||||
return false, nil
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount: given a mount point, find the device name from its global mount point
|
||||
func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||
@ -353,6 +348,63 @@ func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return doMakeRShared(path, procMountInfoPath)
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
var pathType FileType
|
||||
finfo, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
return pathType, fmt.Errorf("path %q does not exist", pathname)
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return pathType, err
|
||||
}
|
||||
|
||||
mode := finfo.Sys().(*syscall.Stat_t).Mode
|
||||
switch mode & syscall.S_IFMT {
|
||||
case syscall.S_IFSOCK:
|
||||
return FileTypeSocket, nil
|
||||
case syscall.S_IFBLK:
|
||||
return FileTypeBlockDev, nil
|
||||
case syscall.S_IFCHR:
|
||||
return FileTypeBlockDev, nil
|
||||
case syscall.S_IFDIR:
|
||||
return FileTypeDirectory, nil
|
||||
case syscall.S_IFREG:
|
||||
return FileTypeFile, nil
|
||||
}
|
||||
|
||||
return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) ExistsPath(pathname string) bool {
|
||||
_, err := os.Stat(pathname)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// formatAndMount uses unix utils to format and mount the given disk
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
options = append(options, "defaults")
|
||||
|
@ -18,6 +18,10 @@ limitations under the License.
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Mounter struct {
|
||||
mounterPath string
|
||||
}
|
||||
@ -74,3 +78,23 @@ func (mounter *Mounter) MakeRShared(path string) error {
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
return FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *Mounter) ExistsPath(pathname string) bool {
|
||||
return true
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
@ -167,6 +168,67 @@ func (mounter *Mounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFileType checks for sockets/block/character devices
|
||||
func (mounter *Mounter) GetFileType(pathname string) (FileType, error) {
|
||||
var pathType FileType
|
||||
info, err := os.Stat(pathname)
|
||||
if os.IsNotExist(err) {
|
||||
return pathType, fmt.Errorf("path %q does not exist", pathname)
|
||||
}
|
||||
// err in call to os.Stat
|
||||
if err != nil {
|
||||
return pathType, err
|
||||
}
|
||||
|
||||
mode := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
||||
switch mode & syscall.S_IFMT {
|
||||
case syscall.S_IFSOCK:
|
||||
return FileTypeSocket, nil
|
||||
case syscall.S_IFBLK:
|
||||
return FileTypeBlockDev, nil
|
||||
case syscall.S_IFCHR:
|
||||
return FileTypeCharDev, nil
|
||||
case syscall.S_IFDIR:
|
||||
return FileTypeDirectory, nil
|
||||
case syscall.S_IFREG:
|
||||
return FileTypeFile, nil
|
||||
}
|
||||
|
||||
return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
|
||||
}
|
||||
|
||||
// MakeFile creates a new directory
|
||||
func (mounter *Mounter) MakeDir(pathname string) error {
|
||||
err := os.MkdirAll(pathname, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeFile creates an empty file
|
||||
func (mounter *Mounter) MakeFile(pathname string) error {
|
||||
f, err := os.OpenFile(pathname, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExistsPath checks whether the path exists
|
||||
func (mounter *Mounter) ExistsPath(pathname string) bool {
|
||||
_, err := os.Stat(pathname)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
|
||||
// Try to mount the disk
|
||||
glog.V(4).Infof("Attempting to formatAndMount disk: %s %s %s", fstype, source, target)
|
||||
|
@ -209,7 +209,9 @@ func (n *NsenterMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
|
||||
// to a device.
|
||||
func (n *NsenterMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return pathIsDevice(pathname)
|
||||
pathType, err := n.GetFileType(pathname)
|
||||
isDevice := pathType == FileTypeCharDev || pathType == FileTypeBlockDev
|
||||
return isDevice, err
|
||||
}
|
||||
|
||||
//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
|
||||
@ -220,3 +222,51 @@ func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (st
|
||||
func (n *NsenterMounter) MakeRShared(path string) error {
|
||||
return doMakeRShared(path, hostProcMountinfoPath)
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) GetFileType(pathname string) (FileType, error) {
|
||||
var pathType FileType
|
||||
outputBytes, err := mounter.ne.Exec("stat", []string{"-L", `--printf "%F"`, pathname}).CombinedOutput()
|
||||
if err != nil {
|
||||
return pathType, err
|
||||
}
|
||||
|
||||
switch string(outputBytes) {
|
||||
case "socket":
|
||||
return FileTypeSocket, nil
|
||||
case "character special file":
|
||||
return FileTypeCharDev, nil
|
||||
case "block special file":
|
||||
return FileTypeBlockDev, nil
|
||||
case "directory":
|
||||
return FileTypeDirectory, nil
|
||||
case "regular file":
|
||||
return FileTypeFile, nil
|
||||
}
|
||||
|
||||
return pathType, fmt.Errorf("only recognise file, directory, socket, block device and character device")
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) MakeDir(pathname string) error {
|
||||
args := []string{"-p", pathname}
|
||||
if _, err := mounter.ne.Exec("mkdir", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) MakeFile(pathname string) error {
|
||||
args := []string{pathname}
|
||||
if _, err := mounter.ne.Exec("touch", args).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *NsenterMounter) ExistsPath(pathname string) bool {
|
||||
args := []string{pathname}
|
||||
_, err := mounter.ne.Exec("ls", args).CombinedOutput()
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -18,6 +18,10 @@ limitations under the License.
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type NsenterMounter struct{}
|
||||
|
||||
func NewNsenterMounter() *NsenterMounter {
|
||||
@ -65,3 +69,19 @@ func (*NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (stri
|
||||
func (*NsenterMounter) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) GetFileType(_ string) (FileType, error) {
|
||||
return FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*NsenterMounter) ExistsPath(pathname string) bool {
|
||||
return true
|
||||
}
|
||||
|
@ -34,27 +34,51 @@ var _ mount.Interface = &fakeMounter{}
|
||||
func (mounter *fakeMounter) Mount(source string, target string, fstype string, options []string) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) Unmount(target string) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) List() ([]mount.MountPoint, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter fakeMounter) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) PathIsDevice(pathname string) (bool, error) {
|
||||
return false, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
return mp.Path == dir
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) IsNotMountPoint(dir string) (bool, error) {
|
||||
return mount.IsNotMountPoint(mounter, dir)
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) GetFileType(pathname string) (mount.FileType, error) {
|
||||
return mount.FileType("fake"), errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) ExistsPath(pathname string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
name := path.Base(file)
|
||||
if strings.HasPrefix(name, "mount") {
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util/volumehelper"
|
||||
"k8s.io/kubernetes/pkg/volume/validation"
|
||||
@ -113,8 +114,9 @@ func (plugin *hostPathPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts vo
|
||||
pathType = hostPathVolumeSource.Type
|
||||
}
|
||||
return &hostPathMounter{
|
||||
hostPath: &hostPath{path: path, pathType: pathType, containerized: opts.Containerized},
|
||||
hostPath: &hostPath{path: path, pathType: pathType},
|
||||
readOnly: readOnly,
|
||||
mounter: plugin.host.GetMounter(plugin.GetPluginName()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -182,9 +184,8 @@ func newProvisioner(options volume.VolumeOptions, host volume.VolumeHost, plugin
|
||||
// HostPath volumes represent a bare host file or directory mount.
|
||||
// The direct at the specified path will be directly exposed to the container.
|
||||
type hostPath struct {
|
||||
path string
|
||||
pathType *v1.HostPathType
|
||||
containerized bool
|
||||
path string
|
||||
pathType *v1.HostPathType
|
||||
volume.MetricsNil
|
||||
}
|
||||
|
||||
@ -195,6 +196,7 @@ func (hp *hostPath) GetPath() string {
|
||||
type hostPathMounter struct {
|
||||
*hostPath
|
||||
readOnly bool
|
||||
mounter mount.Interface
|
||||
}
|
||||
|
||||
var _ volume.Mounter = &hostPathMounter{}
|
||||
@ -224,7 +226,7 @@ func (b *hostPathMounter) SetUp(fsGroup *int64) error {
|
||||
if *b.pathType == v1.HostPathUnset {
|
||||
return nil
|
||||
}
|
||||
return checkType(b.GetPath(), b.pathType, b.containerized)
|
||||
return checkType(b.GetPath(), b.pathType, b.mounter)
|
||||
}
|
||||
|
||||
// SetUpAt does not make sense for host paths - probably programmer error.
|
||||
@ -340,132 +342,77 @@ type hostPathTypeChecker interface {
|
||||
GetPath() string
|
||||
}
|
||||
|
||||
type fileTypeChecker interface {
|
||||
getFileType(fileInfo os.FileInfo) (v1.HostPathType, error)
|
||||
}
|
||||
|
||||
// this is implemented in per-OS files
|
||||
type defaultFileTypeChecker struct{}
|
||||
|
||||
type osFileTypeChecker struct {
|
||||
type fileTypeChecker struct {
|
||||
path string
|
||||
exists bool
|
||||
info os.FileInfo
|
||||
checker fileTypeChecker
|
||||
mounter mount.Interface
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) Exists() bool {
|
||||
return ftc.exists
|
||||
func (ftc *fileTypeChecker) Exists() bool {
|
||||
return ftc.mounter.ExistsPath(ftc.path)
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) IsFile() bool {
|
||||
func (ftc *fileTypeChecker) IsFile() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
return !ftc.info.IsDir()
|
||||
return !ftc.IsDir()
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) MakeFile() error {
|
||||
f, err := os.OpenFile(ftc.path, os.O_CREATE, os.FileMode(0644))
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (ftc *fileTypeChecker) MakeFile() error {
|
||||
return ftc.mounter.MakeFile(ftc.path)
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) IsDir() bool {
|
||||
func (ftc *fileTypeChecker) IsDir() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
return ftc.info.IsDir()
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) MakeDir() error {
|
||||
err := os.MkdirAll(ftc.path, os.FileMode(0755))
|
||||
if err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) IsBlock() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
|
||||
blkDevType, err := ftc.checker.getFileType(ftc.info)
|
||||
pathType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return blkDevType == v1.HostPathBlockDev
|
||||
return string(pathType) == string(v1.HostPathDirectory)
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) IsChar() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
func (ftc *fileTypeChecker) MakeDir() error {
|
||||
return ftc.mounter.MakeDir(ftc.path)
|
||||
}
|
||||
|
||||
charDevType, err := ftc.checker.getFileType(ftc.info)
|
||||
func (ftc *fileTypeChecker) IsBlock() bool {
|
||||
blkDevType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return charDevType == v1.HostPathCharDev
|
||||
return string(blkDevType) == string(v1.HostPathBlockDev)
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) IsSocket() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
|
||||
socketType, err := ftc.checker.getFileType(ftc.info)
|
||||
func (ftc *fileTypeChecker) IsChar() bool {
|
||||
charDevType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return socketType == v1.HostPathSocket
|
||||
return string(charDevType) == string(v1.HostPathCharDev)
|
||||
}
|
||||
|
||||
func (ftc *osFileTypeChecker) GetPath() string {
|
||||
func (ftc *fileTypeChecker) IsSocket() bool {
|
||||
socketType, err := ftc.mounter.GetFileType(ftc.path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return string(socketType) == string(v1.HostPathSocket)
|
||||
}
|
||||
|
||||
func (ftc *fileTypeChecker) GetPath() string {
|
||||
return ftc.path
|
||||
}
|
||||
|
||||
func newOSFileTypeChecker(path string, checker fileTypeChecker) (hostPathTypeChecker, error) {
|
||||
ftc := osFileTypeChecker{path: path, checker: checker}
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
ftc.exists = false
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ftc.info = info
|
||||
ftc.exists = true
|
||||
}
|
||||
return &ftc, nil
|
||||
func newFileTypeChecker(path string, mounter mount.Interface) hostPathTypeChecker {
|
||||
return &fileTypeChecker{path: path, mounter: mounter}
|
||||
}
|
||||
|
||||
func checkType(path string, pathType *v1.HostPathType, containerized bool) error {
|
||||
var ftc hostPathTypeChecker
|
||||
var err error
|
||||
if containerized {
|
||||
// For a containerized kubelet, use nsenter to run commands in
|
||||
// the host's mount namespace.
|
||||
// TODO(dixudx): setns into docker's mount namespace, and then run the exact same go code for checks/setup
|
||||
ftc, err = newNsenterFileTypeChecker(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ftc, err = newOSFileTypeChecker(path, &defaultFileTypeChecker{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return checkTypeInternal(ftc, pathType)
|
||||
// checkType checks whether the given path is the exact pathType
|
||||
func checkType(path string, pathType *v1.HostPathType, mounter mount.Interface) error {
|
||||
return checkTypeInternal(newFileTypeChecker(path, mounter), pathType)
|
||||
}
|
||||
|
||||
func checkTypeInternal(ftc hostPathTypeChecker, pathType *v1.HostPathType) error {
|
||||
|
@ -1,5 +1,3 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
@ -30,6 +28,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
utilfile "k8s.io/kubernetes/pkg/util/file"
|
||||
utilmount "k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumetest "k8s.io/kubernetes/pkg/volume/testing"
|
||||
)
|
||||
@ -323,8 +322,58 @@ type fakeFileTypeChecker struct {
|
||||
desiredType string
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) getFileType(_ os.FileInfo) (v1.HostPathType, error) {
|
||||
return *newHostPathType(fftc.desiredType), nil
|
||||
func (fftc *fakeFileTypeChecker) Mount(source string, target string, fstype string, options []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) Unmount(target string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) List() ([]utilmount.MountPoint, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (fftc *fakeFileTypeChecker) IsMountPointMatch(mp utilmount.MountPoint, dir string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) IsNotMountPoint(file string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) DeviceOpened(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
func (fftc *fakeFileTypeChecker) PathIsDevice(pathname string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "fake", nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) MakeFile(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) MakeDir(pathname string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) ExistsPath(pathname string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (fftc *fakeFileTypeChecker) GetFileType(_ string) (utilmount.FileType, error) {
|
||||
return utilmount.FileType(fftc.desiredType), nil
|
||||
}
|
||||
|
||||
func setUp() error {
|
||||
@ -363,14 +412,16 @@ func TestOSFileTypeChecker(t *testing.T) {
|
||||
isChar bool
|
||||
}{
|
||||
{
|
||||
name: "Existing Folder",
|
||||
path: "/tmp/ExistingFolder",
|
||||
isDir: true,
|
||||
name: "Existing Folder",
|
||||
path: "/tmp/ExistingFolder",
|
||||
desiredType: string(utilmount.FileTypeDirectory),
|
||||
isDir: true,
|
||||
},
|
||||
{
|
||||
name: "Existing File",
|
||||
path: "/tmp/ExistingFolder/foo",
|
||||
isFile: true,
|
||||
name: "Existing File",
|
||||
path: "/tmp/ExistingFolder/foo",
|
||||
desiredType: string(utilmount.FileTypeFile),
|
||||
isFile: true,
|
||||
},
|
||||
{
|
||||
name: "Existing Socket File",
|
||||
@ -393,11 +444,8 @@ func TestOSFileTypeChecker(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
oftc, err := newOSFileTypeChecker(tc.path,
|
||||
&fakeFileTypeChecker{desiredType: tc.desiredType})
|
||||
if err != nil {
|
||||
t.Errorf("[%d: %q] expect nil, but got %v", i, tc.name, err)
|
||||
}
|
||||
fakeFTC := &fakeFileTypeChecker{desiredType: tc.desiredType}
|
||||
oftc := newFileTypeChecker(tc.path, fakeFTC)
|
||||
|
||||
path := oftc.GetPath()
|
||||
if path != tc.path {
|
||||
|
@ -1,40 +0,0 @@
|
||||
// +build linux darwin
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package host_path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func (dftc *defaultFileTypeChecker) getFileType(info os.FileInfo) (v1.HostPathType, error) {
|
||||
mode := info.Sys().(*syscall.Stat_t).Mode
|
||||
switch mode & syscall.S_IFMT {
|
||||
case syscall.S_IFSOCK:
|
||||
return v1.HostPathSocket, nil
|
||||
case syscall.S_IFBLK:
|
||||
return v1.HostPathBlockDev, nil
|
||||
case syscall.S_IFCHR:
|
||||
return v1.HostPathCharDev, nil
|
||||
}
|
||||
return "", fmt.Errorf("only recognise socket, block device and character device")
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package host_path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func (dftc *defaultFileTypeChecker) getFileType(info os.FileInfo) (v1.HostPathType, error) {
|
||||
mode := info.Sys().(*syscall.Win32FileAttributeData).FileAttributes
|
||||
switch mode & syscall.S_IFMT {
|
||||
case syscall.S_IFSOCK:
|
||||
return v1.HostPathSocket, nil
|
||||
case syscall.S_IFBLK:
|
||||
return v1.HostPathBlockDev, nil
|
||||
case syscall.S_IFCHR:
|
||||
return v1.HostPathCharDev, nil
|
||||
}
|
||||
return "", fmt.Errorf("only recognise socket, block device and character device")
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package host_path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
hostProcMountsNamespace = "/rootfs/proc/1/ns/mnt"
|
||||
nsenterCmd = "nsenter"
|
||||
statCmd = "stat"
|
||||
touchCmd = "touch"
|
||||
mkdirCmd = "mkdir"
|
||||
)
|
||||
|
||||
// nsenterFileTypeChecker is part of experimental support for running the kubelet
|
||||
// in a container. nsenterFileTypeChecker works by executing "nsenter" to run commands in
|
||||
// the host's mount namespace.
|
||||
//
|
||||
// nsenterFileTypeChecker requires:
|
||||
//
|
||||
// 1. The host's root filesystem must be available at "/rootfs";
|
||||
// 2. The "nsenter" binary must be on the Kubelet process' PATH in the container's
|
||||
// filesystem;
|
||||
// 3. The Kubelet process must have CAP_SYS_ADMIN (required by "nsenter"); at
|
||||
// the present, this effectively means that the kubelet is running in a
|
||||
// privileged container;
|
||||
// 4. The host image must have "stat", "touch", "mkdir" binaries in "/bin", "/usr/sbin", or "/usr/bin";
|
||||
|
||||
type nsenterFileTypeChecker struct {
|
||||
path string
|
||||
exists bool
|
||||
}
|
||||
|
||||
func newNsenterFileTypeChecker(path string) (hostPathTypeChecker, error) {
|
||||
ftc := &nsenterFileTypeChecker{path: path}
|
||||
ftc.Exists()
|
||||
return ftc, nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) Exists() bool {
|
||||
args := []string{
|
||||
fmt.Sprintf("--mount=%s", hostProcMountsNamespace),
|
||||
"--",
|
||||
"ls",
|
||||
ftc.path,
|
||||
}
|
||||
exec := exec.New()
|
||||
_, err := exec.Command(nsenterCmd, args...).CombinedOutput()
|
||||
if err == nil {
|
||||
ftc.exists = true
|
||||
}
|
||||
return ftc.exists
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsFile() bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
return !ftc.IsDir()
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) MakeFile() error {
|
||||
args := []string{
|
||||
fmt.Sprintf("--mount=%s", hostProcMountsNamespace),
|
||||
"--",
|
||||
touchCmd,
|
||||
ftc.path,
|
||||
}
|
||||
exec := exec.New()
|
||||
if _, err := exec.Command(nsenterCmd, args...).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsDir() bool {
|
||||
return ftc.checkMimetype("directory")
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) MakeDir() error {
|
||||
args := []string{
|
||||
fmt.Sprintf("--mount=%s", hostProcMountsNamespace),
|
||||
"--",
|
||||
mkdirCmd,
|
||||
"-p",
|
||||
ftc.path,
|
||||
}
|
||||
exec := exec.New()
|
||||
if _, err := exec.Command(nsenterCmd, args...).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsBlock() bool {
|
||||
return ftc.checkMimetype("block special file")
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsChar() bool {
|
||||
return ftc.checkMimetype("character special file")
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsSocket() bool {
|
||||
return ftc.checkMimetype("socket")
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) GetPath() string {
|
||||
return ftc.path
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) checkMimetype(checkedType string) bool {
|
||||
if !ftc.Exists() {
|
||||
return false
|
||||
}
|
||||
|
||||
args := []string{
|
||||
fmt.Sprintf("--mount=%s", hostProcMountsNamespace),
|
||||
"--",
|
||||
statCmd,
|
||||
"-L",
|
||||
`--printf "%F"`,
|
||||
ftc.path,
|
||||
}
|
||||
exec := exec.New()
|
||||
outputBytes, err := exec.Command(nsenterCmd, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return string(outputBytes) == checkedType
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package host_path
|
||||
|
||||
type nsenterFileTypeChecker struct {
|
||||
path string
|
||||
exists bool
|
||||
}
|
||||
|
||||
func newNsenterFileTypeChecker(path string) (hostPathTypeChecker, error) {
|
||||
ftc := &nsenterFileTypeChecker{path: path}
|
||||
ftc.Exists()
|
||||
return ftc, nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) Exists() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsFile() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) MakeFile() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) MakeDir() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsBlock() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsChar() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) IsSocket() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ftc *nsenterFileTypeChecker) GetPath() string {
|
||||
return ftc.path
|
||||
}
|
@ -69,8 +69,6 @@ type VolumeOptions struct {
|
||||
CloudTags *map[string]string
|
||||
// Volume provisioning parameters from StorageClass
|
||||
Parameters map[string]string
|
||||
// This flag helps identify whether kubelet is running in a container
|
||||
Containerized bool
|
||||
}
|
||||
|
||||
type DynamicPluginProber interface {
|
||||
|
Loading…
Reference in New Issue
Block a user