Update go dependencies and cleanup deprecated packages

This commit is contained in:
Manuel de Brito Fontes 2018-01-07 12:10:25 -03:00
parent 03a1e20fde
commit 44fd79d061
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1099 changed files with 75691 additions and 31913 deletions

View file

@ -11,12 +11,14 @@ go_library(
srcs = [
"doc.go",
"exec.go",
"exec_mount_unsupported.go",
"fake.go",
"mount.go",
"mount_unsupported.go",
"nsenter_mount_unsupported.go",
] + select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"exec_mount.go",
"mount_linux.go",
"nsenter_mount.go",
],
@ -25,12 +27,14 @@ go_library(
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/util/mount",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"//pkg/util/io:go_default_library",
"//pkg/util/nsenter:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
@ -44,6 +48,7 @@ go_test(
"safe_format_and_mount_test.go",
] + select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"exec_mount_test.go",
"mount_linux_test.go",
"nsenter_mount_test.go",
],
@ -52,6 +57,7 @@ go_test(
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/util/mount",
library = ":go_default_library",
deps = ["//vendor/k8s.io/utils/exec/testing:go_default_library"],
)

140
vendor/k8s.io/kubernetes/pkg/util/mount/exec_mount.go generated vendored Normal file
View file

@ -0,0 +1,140 @@
// +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 mount
import (
"fmt"
"github.com/golang/glog"
)
// ExecMounter is a mounter that uses provided Exec interface to mount and
// unmount a filesystem. For all other calls it uses a wrapped mounter.
type execMounter struct {
wrappedMounter Interface
exec Exec
}
func NewExecMounter(exec Exec, wrapped Interface) Interface {
return &execMounter{
wrappedMounter: wrapped,
exec: exec,
}
}
// execMounter implements mount.Interface
var _ Interface = &execMounter{}
// Mount runs mount(8) using given exec interface.
func (m *execMounter) Mount(source string, target string, fstype string, options []string) error {
bind, bindRemountOpts := isBind(options)
if bind {
err := m.doExecMount(source, target, fstype, []string{"bind"})
if err != nil {
return err
}
return m.doExecMount(source, target, fstype, bindRemountOpts)
}
return m.doExecMount(source, target, fstype, options)
}
// doExecMount calls exec(mount <waht> <where>) using given exec interface.
func (m *execMounter) doExecMount(source, target, fstype string, options []string) error {
glog.V(5).Infof("Exec Mounting %s %s %s %v", source, target, fstype, options)
mountArgs := makeMountArgs(source, target, fstype, options)
output, err := m.exec.Run("mount", mountArgs...)
glog.V(5).Infof("Exec mounted %v: %v: %s", mountArgs, err, string(output))
if err != nil {
return fmt.Errorf("mount failed: %v\nMounting command: %s\nMounting arguments: %s %s %s %v\nOutput: %s\n",
err, "mount", source, target, fstype, options, string(output))
}
return err
}
// Unmount runs umount(8) using given exec interface.
func (m *execMounter) Unmount(target string) error {
outputBytes, err := m.exec.Run("umount", target)
if err == nil {
glog.V(5).Infof("Exec unmounted %s: %s", target, string(outputBytes))
} else {
glog.V(5).Infof("Failed to exec unmount %s: err: %q, umount output: %s", target, err, string(outputBytes))
}
return err
}
// List returns a list of all mounted filesystems.
func (m *execMounter) List() ([]MountPoint, error) {
return m.wrappedMounter.List()
}
// IsLikelyNotMountPoint determines whether a path is a mountpoint.
func (m *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return m.wrappedMounter.IsLikelyNotMountPoint(file)
}
// DeviceOpened checks if block device in use by calling Open with O_EXCL flag.
// Returns true if open returns errno EBUSY, and false if errno is nil.
// Returns an error if errno is any error other than EBUSY.
// Returns with error if pathname is not a device.
func (m *execMounter) DeviceOpened(pathname string) (bool, error) {
return m.wrappedMounter.DeviceOpened(pathname)
}
// PathIsDevice uses FileInfo returned from os.Stat to check if path refers
// to a device.
func (m *execMounter) PathIsDevice(pathname string) (bool, error) {
return m.wrappedMounter.PathIsDevice(pathname)
}
//GetDeviceNameFromMount given a mount point, find the volume id from checking /proc/mounts
func (m *execMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
return m.wrappedMounter.GetDeviceNameFromMount(mountPath, pluginDir)
}
func (m *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
return m.wrappedMounter.IsMountPointMatch(mp, dir)
}
func (m *execMounter) IsNotMountPoint(dir string) (bool, error) {
return m.wrappedMounter.IsNotMountPoint(dir)
}
func (m *execMounter) MakeRShared(path string) error {
return m.wrappedMounter.MakeRShared(path)
}
func (m *execMounter) GetFileType(pathname string) (FileType, error) {
return m.wrappedMounter.GetFileType(pathname)
}
func (m *execMounter) MakeFile(pathname string) error {
return m.wrappedMounter.MakeFile(pathname)
}
func (m *execMounter) MakeDir(pathname string) error {
return m.wrappedMounter.MakeDir(pathname)
}
func (m *execMounter) ExistsPath(pathname string) bool {
return m.wrappedMounter.ExistsPath(pathname)
}

View file

@ -0,0 +1,153 @@
// +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 mount
import (
"fmt"
"reflect"
"strings"
"testing"
)
var (
sourcePath = "/mnt/srv"
destinationPath = "/mnt/dst"
fsType = "xfs"
mountOptions = []string{"vers=1", "foo=bar"}
)
func TestMount(t *testing.T) {
exec := NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
if cmd != "mount" {
t.Errorf("expected mount command, got %q", cmd)
}
// mount -t fstype -o options source target
expectedArgs := []string{"-t", fsType, "-o", strings.Join(mountOptions, ","), sourcePath, destinationPath}
if !reflect.DeepEqual(expectedArgs, args) {
t.Errorf("expected arguments %q, got %q", strings.Join(expectedArgs, " "), strings.Join(args, " "))
}
return nil, nil
})
wrappedMounter := &fakeMounter{t}
mounter := NewExecMounter(exec, wrappedMounter)
mounter.Mount(sourcePath, destinationPath, fsType, mountOptions)
}
func TestBindMount(t *testing.T) {
cmdCount := 0
exec := NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
cmdCount++
if cmd != "mount" {
t.Errorf("expected mount command, got %q", cmd)
}
var expectedArgs []string
switch cmdCount {
case 1:
// mount -t fstype -o "bind" source target
expectedArgs = []string{"-t", fsType, "-o", "bind", sourcePath, destinationPath}
case 2:
// mount -t fstype -o "remount,opts" source target
expectedArgs = []string{"-t", fsType, "-o", "remount," + strings.Join(mountOptions, ","), sourcePath, destinationPath}
}
if !reflect.DeepEqual(expectedArgs, args) {
t.Errorf("expected arguments %q, got %q", strings.Join(expectedArgs, " "), strings.Join(args, " "))
}
return nil, nil
})
wrappedMounter := &fakeMounter{t}
mounter := NewExecMounter(exec, wrappedMounter)
bindOptions := append(mountOptions, "bind")
mounter.Mount(sourcePath, destinationPath, fsType, bindOptions)
}
func TestUnmount(t *testing.T) {
exec := NewFakeExec(func(cmd string, args ...string) ([]byte, error) {
if cmd != "umount" {
t.Errorf("expected unmount command, got %q", cmd)
}
// unmount $target
expectedArgs := []string{destinationPath}
if !reflect.DeepEqual(expectedArgs, args) {
t.Errorf("expected arguments %q, got %q", strings.Join(expectedArgs, " "), strings.Join(args, " "))
}
return nil, nil
})
wrappedMounter := &fakeMounter{t}
mounter := NewExecMounter(exec, wrappedMounter)
mounter.Unmount(destinationPath)
}
/* Fake wrapped mounter */
type fakeMounter struct {
t *testing.T
}
func (fm *fakeMounter) Mount(source string, target string, fstype string, options []string) error {
// Mount() of wrapped mounter should never be called. We call exec instead.
fm.t.Errorf("Unexpected wrapped mount call")
return fmt.Errorf("Unexpected wrapped mount call")
}
func (fm *fakeMounter) Unmount(target string) error {
// umount() of wrapped mounter should never be called. We call exec instead.
fm.t.Errorf("Unexpected wrapped mount call")
return fmt.Errorf("Unexpected wrapped mount call")
}
func (fm *fakeMounter) List() ([]MountPoint, error) {
return nil, nil
}
func (fm *fakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
return false
}
func (fm *fakeMounter) IsNotMountPoint(file string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) DeviceOpened(pathname string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) PathIsDevice(pathname string) (bool, error) {
return false, nil
}
func (fm *fakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
return "", nil
}
func (fm *fakeMounter) MakeRShared(path string) error {
return nil
}
func (fm *fakeMounter) MakeFile(pathname string) error {
return nil
}
func (fm *fakeMounter) MakeDir(pathname string) error {
return nil
}
func (fm *fakeMounter) ExistsPath(pathname string) bool {
return false
}
func (fm *fakeMounter) GetFileType(pathname string) (FileType, error) {
return FileTypeFile, nil
}

View file

@ -0,0 +1,87 @@
// +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 mount
import (
"errors"
)
type execMounter struct{}
// ExecMounter is a mounter that uses provided Exec interface to mount and
// unmount a filesystem. For all other calls it uses a wrapped mounter.
func NewExecMounter(exec Exec, wrapped Interface) Interface {
return &execMounter{}
}
func (mounter *execMounter) Mount(source string, target string, fstype string, options []string) error {
return nil
}
func (mounter *execMounter) Unmount(target string) error {
return nil
}
func (mounter *execMounter) List() ([]MountPoint, error) {
return []MountPoint{}, nil
}
func (mounter *execMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
return (mp.Path == dir)
}
func (mounter *execMounter) IsNotMountPoint(dir string) (bool, error) {
return IsNotMountPoint(mounter, dir)
}
func (mounter *execMounter) IsLikelyNotMountPoint(file string) (bool, error) {
return true, nil
}
func (mounter *execMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
return "", nil
}
func (mounter *execMounter) DeviceOpened(pathname string) (bool, error) {
return false, nil
}
func (mounter *execMounter) PathIsDevice(pathname string) (bool, error) {
return true, nil
}
func (mounter *execMounter) MakeRShared(path string) error {
return nil
}
func (mounter *execMounter) GetFileType(pathname string) (FileType, error) {
return FileType("fake"), errors.New("not implemented")
}
func (mounter *execMounter) MakeDir(pathname string) error {
return nil
}
func (mounter *execMounter) MakeFile(pathname string) error {
return nil
}
func (mounter *execMounter) ExistsPath(pathname string) bool {
return true
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package mount
import (
"os"
"path/filepath"
"sync"
@ -125,7 +126,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) {
@ -136,6 +137,11 @@ func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
f.mutex.Lock()
defer f.mutex.Unlock()
_, err := os.Stat(file)
if err != nil {
return true, err
}
// If file is a symlink, get its absolute path
absFile, err := filepath.EvalSymlinks(file)
if err != nil {
@ -175,3 +181,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
}

View file

@ -22,10 +22,17 @@ import (
"path/filepath"
)
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 {
@ -65,6 +72,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,

View file

@ -44,9 +44,6 @@ const (
procMountsPath = "/proc/mounts"
// Location of the mountinfo file
procMountInfoPath = "/proc/self/mountinfo"
)
const (
// 'fsck' found errors and corrected them
fsckErrorsCorrected = 1
// 'fsck' found errors but exited without correcting them
@ -73,12 +70,12 @@ func New(mounterPath string) Interface {
// Mount mounts source to target as fstype with given options. 'source' and 'fstype' must
// be an emtpy string in case it's not required, e.g. for remount, or for auto filesystem
// type, where kernel handles fs type for you. The mount 'options' is a list of options,
// type, where kernel handles fstype for you. The mount 'options' is a list of options,
// currently come from mount(8), e.g. "ro", "remount", "bind", etc. If no more option is
// required, call Mount with an empty string list or nil.
func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error {
// Path to mounter binary if containerized mounter is needed. Otherwise, it is set to empty.
// All Linux distros are expected to be shipped with a mount utility that an support bind mounts.
// All Linux distros are expected to be shipped with a mount utility that a support bind mounts.
mounterPath := ""
bind, bindRemountOpts := isBind(options)
if bind {
@ -292,17 +289,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
@ -322,23 +331,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)
@ -418,9 +410,64 @@ func parseProcMounts(content []byte) ([]MountPoint, error) {
}
func (mounter *Mounter) MakeRShared(path string) error {
mountCmd := defaultMountCommand
mountArgs := []string{}
return doMakeRShared(path, procMountInfoPath, mountCmd, mountArgs)
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
@ -451,7 +498,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
if mountErr != nil {
// Mount failed. This indicates either that the disk is unformatted or
// it contains an unexpected filesystem.
existingFormat, err := mounter.getDiskFormat(source)
existingFormat, err := mounter.GetDiskFormat(source)
if err != nil {
return err
}
@ -489,8 +536,8 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
return mountErr
}
// diskLooksUnformatted uses 'lsblk' to see if the given disk is unformated
func (mounter *SafeFormatAndMount) getDiskFormat(disk string) (string, error) {
// GetDiskFormat uses 'lsblk' to see if the given disk is unformated
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
args := []string{"-n", "-o", "FSTYPE", disk}
glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args)
dataOut, err := mounter.Exec.Run("lsblk", args...)
@ -591,7 +638,7 @@ func parseMountInfo(filename string) ([]mountInfo, error) {
// path is shared and bind-mounts it as rshared if needed. mountCmd and
// mountArgs are expected to contain mount-like command, doMakeRShared will add
// '--bind <path> <path>' and '--make-rshared <path>' to mountArgs.
func doMakeRShared(path string, mountInfoFilename string, mountCmd string, mountArgs []string) error {
func doMakeRShared(path string, mountInfoFilename string) error {
shared, err := isShared(path, mountInfoFilename)
if err != nil {
return err

View file

@ -18,6 +18,10 @@ limitations under the License.
package mount
import (
"errors"
)
type Mounter struct {
mounterPath string
}
@ -82,9 +86,25 @@ func (mounter *Mounter) MakeRShared(path string) error {
}
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
return nil
return mounter.Interface.Mount(source, target, fstype, options)
}
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
}

View file

@ -26,6 +26,7 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/golang/glog"
)
@ -75,8 +76,24 @@ func (mounter *Mounter) Mount(source string, target string, fstype string, optio
return nil
}
// empty implementation for mounting azure file
return os.MkdirAll(target, 0755)
// currently only cifs mount is supported
if strings.ToLower(fstype) != "cifs" {
return fmt.Errorf("azureMount: only cifs mount is supported now, fstype: %q, mounting source (%q), target (%q), with options (%q)", fstype, source, target, options)
}
cmdLine := fmt.Sprintf(`$User = "%s";$PWord = ConvertTo-SecureString -String "%s" -AsPlainText -Force;`+
`$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord`,
options[0], options[1])
bindSource = source
cmdLine += fmt.Sprintf(";New-SmbGlobalMapping -RemotePath %s -Credential $Credential", source)
if output, err := exec.Command("powershell", "/c", cmdLine).CombinedOutput(); err != nil {
// we don't return error here, even though New-SmbGlobalMapping failed, we still make it successful,
// will return error when Windows 2016 RS3 is ready on azure
glog.Errorf("azureMount: SmbGlobalMapping failed: %v, only SMB mount is supported now, output: %q", err, string(output))
return os.MkdirAll(target, 0755)
}
}
if output, err := exec.Command("cmd", "/c", "mklink", "/D", target, bindSource).CombinedOutput(); err != nil {
@ -185,6 +202,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)

View file

@ -24,12 +24,6 @@ import (
"testing"
)
func TestGetAvailableDriveLetter(t *testing.T) {
if _, err := getAvailableDriveLetter(); err != nil {
t.Errorf("getAvailableDriveLetter test failed : %v", err)
}
}
func TestNormalizeWindowsPath(t *testing.T) {
path := `/var/lib/kubelet/pods/146f8428-83e7-11e7-8dd4-000d3a31dac4/volumes/kubernetes.io~azure-disk`
normalizedPath := normalizeWindowsPath(path)

View file

@ -25,78 +25,30 @@ import (
"strings"
"github.com/golang/glog"
"k8s.io/utils/exec"
"k8s.io/kubernetes/pkg/util/nsenter"
)
// NsenterMounter is part of experimental support for running the kubelet
// in a container. Currently, all docker containers receive their own mount
// namespaces. NsenterMounter works by executing nsenter to run commands in
const (
// hostProcMountsPath is the default mount path for rootfs
hostProcMountsPath = "/rootfs/proc/1/mounts"
// hostProcMountinfoPath is the default mount info path for rootfs
hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
)
// Currently, all docker containers receive their own mount namespaces.
// NsenterMounter works by executing nsenter to run commands in
// the host's mount namespace.
//
// NsenterMounter requires:
//
// 1. Docker >= 1.6 due to the dependency on the slave propagation mode
// of the bind-mount of the kubelet root directory in the container.
// Docker 1.5 used a private propagation mode for bind-mounts, so mounts
// performed in the host's mount namespace do not propagate out to the
// bind-mount in this docker version.
// 2. The host's root filesystem must be available at /rootfs
// 3. The nsenter binary must be on the Kubelet process' PATH in the container's
// filesystem.
// 4. 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.
// 5. The volume path used by the Kubelet must be the same inside and outside
// the container and be writable by the container (to initialize volume)
// contents. TODO: remove this requirement.
// 6. The host image must have mount, findmnt, and umount binaries in /bin,
// /usr/sbin, or /usr/bin
// 7. The host image should have systemd-run in /bin, /usr/sbin, or /usr/bin
// For more information about mount propagation modes, see:
// https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt
type NsenterMounter struct {
// a map of commands to their paths on the host filesystem
paths map[string]string
ne *nsenter.Nsenter
}
func NewNsenterMounter() *NsenterMounter {
m := &NsenterMounter{
paths: map[string]string{
"mount": "",
"findmnt": "",
"umount": "",
"systemd-run": "",
},
}
// search for the mount command in other locations besides /usr/bin
for binary := range m.paths {
// default to root
m.paths[binary] = filepath.Join("/", binary)
for _, path := range []string{"/bin", "/usr/sbin", "/usr/bin"} {
binPath := filepath.Join(path, binary)
if _, err := os.Stat(filepath.Join(hostRootFsPath, binPath)); err != nil {
continue
}
m.paths[binary] = binPath
break
}
// TODO: error, so that the kubelet can stop if the mounts don't exist
// (don't forget that systemd-run is optional)
}
return m
return &NsenterMounter{ne: nsenter.NewNsenter()}
}
// NsenterMounter implements mount.Interface
var _ = Interface(&NsenterMounter{})
const (
hostRootFsPath = "/rootfs"
hostProcMountsPath = "/rootfs/proc/1/mounts"
hostProcMountinfoPath = "/rootfs/proc/1/mountinfo"
hostMountNamespacePath = "/rootfs/proc/1/ns/mnt"
nsenterPath = "nsenter"
)
// Mount runs mount(8) in the host's root mount namespace. Aside from this
// aspect, Mount has the same semantics as the mounter returned by mount.New()
func (n *NsenterMounter) Mount(source string, target string, fstype string, options []string) error {
@ -116,26 +68,22 @@ func (n *NsenterMounter) Mount(source string, target string, fstype string, opti
// doNsenterMount nsenters the host's mount namespace and performs the
// requested mount.
func (n *NsenterMounter) doNsenterMount(source, target, fstype string, options []string) error {
glog.V(5).Infof("nsenter Mounting %s %s %s %v", source, target, fstype, options)
args := n.makeNsenterArgs(source, target, fstype, options)
glog.V(5).Infof("Mount command: %v %v", nsenterPath, args)
exec := exec.New()
outputBytes, err := exec.Command(nsenterPath, args...).CombinedOutput()
glog.V(5).Infof("nsenter mount %s %s %s %v", source, target, fstype, options)
cmd, args := n.makeNsenterArgs(source, target, fstype, options)
outputBytes, err := n.ne.Exec(cmd, args).CombinedOutput()
if len(outputBytes) != 0 {
glog.V(5).Infof("Output of mounting %s to %s: %v", source, target, string(outputBytes))
}
return err
}
// makeNsenterArgs makes a list of argument to nsenter in order to do the
// requested mount.
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) []string {
mountCmd := n.absHostPath("mount")
func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options []string) (string, []string) {
mountCmd := n.ne.AbsHostPath("mount")
mountArgs := makeMountArgs(source, target, fstype, options)
if systemdRunPath, hasSystemd := n.paths["systemd-run"]; hasSystemd {
if systemdRunPath, hasSystemd := n.ne.SupportsSystemd(); hasSystemd {
// Complete command line:
// nsenter --mount=/rootfs/proc/1/ns/mnt -- /bin/systemd-run --description=... --scope -- /bin/mount -t <type> <what> <where>
// Expected flow is:
@ -165,34 +113,20 @@ func (n *NsenterMounter) makeNsenterArgs(source, target, fstype string, options
// No code here, mountCmd and mountArgs use /bin/mount
}
nsenterArgs := []string{
"--mount=" + hostMountNamespacePath,
"--",
mountCmd,
}
nsenterArgs = append(nsenterArgs, mountArgs...)
return nsenterArgs
return mountCmd, mountArgs
}
// Unmount runs umount(8) in the host's mount namespace.
func (n *NsenterMounter) Unmount(target string) error {
args := []string{
"--mount=" + hostMountNamespacePath,
"--",
n.absHostPath("umount"),
target,
}
args := []string{target}
// No need to execute systemd-run here, it's enough that unmount is executed
// in the host's mount namespace. It will finish appropriate fuse daemon(s)
// running in any scope.
glog.V(5).Infof("Unmount command: %v %v", nsenterPath, args)
exec := exec.New()
outputBytes, err := exec.Command(nsenterPath, args...).CombinedOutput()
glog.V(5).Infof("nsenter unmount args: %v", args)
outputBytes, err := n.ne.Exec("umount", args).CombinedOutput()
if len(outputBytes) != 0 {
glog.V(5).Infof("Output of unmounting %s: %v", target, string(outputBytes))
}
return err
}
@ -207,7 +141,7 @@ func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) {
func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool {
deletedDir := fmt.Sprintf("%s\\040(deleted)", dir)
return ((mp.Path == dir) || (mp.Path == deletedDir))
return (mp.Path == dir) || (mp.Path == deletedDir)
}
// IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt
@ -227,11 +161,9 @@ func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) {
// the first of multiple possible mountpoints using --first-only.
// Also add fstype output to make sure that the output of target file will give the full path
// TODO: Need more refactoring for this function. Track the solution with issue #26996
args := []string{"--mount=" + hostMountNamespacePath, "--", n.absHostPath("findmnt"), "-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
glog.V(5).Infof("findmnt command: %v %v", nsenterPath, args)
exec := exec.New()
out, err := exec.Command(nsenterPath, args...).CombinedOutput()
args := []string{"-o", "target,fstype", "--noheadings", "--first-only", "--target", file}
glog.V(5).Infof("nsenter findmnt args: %v", args)
out, err := n.ne.Exec("findmnt", args).CombinedOutput()
if err != nil {
glog.V(2).Infof("Failed findmnt command for path %s: %v", file, err)
// Different operating systems behave differently for paths which are not mount points.
@ -277,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
@ -285,20 +219,54 @@ func (n *NsenterMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (st
return getDeviceNameFromMount(n, mountPath, pluginDir)
}
func (n *NsenterMounter) absHostPath(command string) string {
path, ok := n.paths[command]
if !ok {
return command
}
return path
func (n *NsenterMounter) MakeRShared(path string) error {
return doMakeRShared(path, hostProcMountinfoPath)
}
func (n *NsenterMounter) MakeRShared(path string) error {
nsenterCmd := nsenterPath
nsenterArgs := []string{
"--mount=" + hostMountNamespacePath,
"--",
n.absHostPath("mount"),
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
}
return doMakeRShared(path, hostProcMountinfoPath, nsenterCmd, nsenterArgs)
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
}

View file

@ -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
}

View file

@ -18,6 +18,8 @@ package mount
import (
"fmt"
"io/ioutil"
"os"
"runtime"
"testing"
@ -50,6 +52,11 @@ func TestSafeFormatAndMount(t *testing.T) {
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
t.Skipf("not supported on GOOS=%s", runtime.GOOS)
}
mntDir, err := ioutil.TempDir(os.TempDir(), "mount")
if err != nil {
t.Fatalf("failed to create tmp dir: %v", err)
}
defer os.RemoveAll(mntDir)
tests := []struct {
description string
fstype string
@ -207,7 +214,7 @@ func TestSafeFormatAndMount(t *testing.T) {
}
device := "/dev/foo"
dest := "/mnt/bar"
dest := mntDir
err := mounter.FormatAndMount(device, dest, test.fstype, test.mountOptions)
if test.expectedError == nil {
if err != nil {