mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
Merge pull request #52401 from andyzhangx/azuredisk-getdevfunc
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. fix warning messages due to GetMountRefs func not implemented in windows **What this PR does / why we need it**: This PR completes the windows implementation of GetMountRefs in mount.go. In linux, the GetMountRefs implementaion is: read `/proc/mounts` and find all mount points, while in Windows, there is no such `/proc/mounts` place which shows all mounting points. There is another way in windows, **we could walk through(by `getAllParentLinks` func) the mount path(symbolic link) and get all symlinks until we got the final device, which is actually a drive**. **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #54670 This PR fixed the warnning issue mentioned in https://github.com/kubernetes/kubernetes/pull/51252 **Special notes for your reviewer**: Some values in the code would be like follwoing: ``` GetMountRefs: mountPath ("\\var\\lib\\kubelet\\pods/4c74b128-92ca-11e7-b86b-000d3a36d70c/volumes/kubernetes.io~azure-disk/pvc-1cc91c70-92ca-11e7-b86b-000d3a36d70c") getAllParentLinks: refs (["" "" "c:\\var\\lib\\kubelet\\plugins\\kubernetes.io\\azure-disk\\mounts\\b1246717734" "G:\\"]) basemountPath c:\var\lib\kubelet\plugins\kubernetes.io\azure-disk\mounts got volumeID b1246717734 ``` **Release note**: ``` fix warning messages due to GetMountRefs func not implemented in windows ```
This commit is contained in:
commit
f34a24e98e
@ -19,12 +19,7 @@ limitations under the License.
|
|||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileType string
|
type FileType string
|
||||||
@ -138,41 +133,6 @@ func (mounter *SafeFormatAndMount) FormatAndMount(source string, target string,
|
|||||||
return mounter.formatAndMount(source, target, fstype, options)
|
return mounter.formatAndMount(source, target, fstype, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMountRefs finds all other references to the device referenced
|
|
||||||
// by mountPath; returns a list of paths.
|
|
||||||
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
|
||||||
mps, err := mounter.List()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Find the device name.
|
|
||||||
deviceName := ""
|
|
||||||
// If mountPath is symlink, need get its target path.
|
|
||||||
slTarget, err := filepath.EvalSymlinks(mountPath)
|
|
||||||
if err != nil {
|
|
||||||
slTarget = mountPath
|
|
||||||
}
|
|
||||||
for i := range mps {
|
|
||||||
if mps[i].Path == slTarget {
|
|
||||||
deviceName = mps[i].Device
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all references to the device.
|
|
||||||
var refs []string
|
|
||||||
if deviceName == "" {
|
|
||||||
glog.Warningf("could not determine device for path: %q", mountPath)
|
|
||||||
} else {
|
|
||||||
for i := range mps {
|
|
||||||
if mps[i].Device == deviceName && mps[i].Path != slTarget {
|
|
||||||
refs = append(refs, mps[i].Path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return refs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMountRefsByDev finds all references to the device provided
|
// GetMountRefsByDev finds all references to the device provided
|
||||||
// by mountPath; returns a list of paths.
|
// by mountPath; returns a list of paths.
|
||||||
func GetMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
|
func GetMountRefsByDev(mounter Interface, mountPath string) ([]string, error) {
|
||||||
@ -239,34 +199,6 @@ func GetDeviceNameFromMount(mounter Interface, mountPath string) (string, int, e
|
|||||||
return device, refCount, nil
|
return device, refCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDeviceNameFromMount find the device name from /proc/mounts in which
|
|
||||||
// the mount path reference should match the given plugin directory. In case no mount path reference
|
|
||||||
// matches, returns the volume name taken from its given mountPath
|
|
||||||
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
|
||||||
refs, err := GetMountRefs(mounter, mountPath)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(refs) == 0 {
|
|
||||||
glog.V(4).Infof("Directory %s is not mounted", mountPath)
|
|
||||||
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
|
||||||
}
|
|
||||||
basemountPath := path.Join(pluginDir, MountsInGlobalPDPath)
|
|
||||||
for _, ref := range refs {
|
|
||||||
if strings.HasPrefix(ref, basemountPath) {
|
|
||||||
volumeID, err := filepath.Rel(basemountPath, ref)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return volumeID, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.Base(mountPath), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotMountPoint determines if a directory is a mountpoint.
|
// IsNotMountPoint determines if a directory is a mountpoint.
|
||||||
// It should return ErrNotExist when the directory does not exist.
|
// It should return ErrNotExist when the directory does not exist.
|
||||||
// This method uses the List() of all mountpoints
|
// This method uses the List() of all mountpoints
|
||||||
|
@ -22,6 +22,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -141,6 +143,41 @@ func (m *Mounter) doMount(mounterPath string, mountCmd string, source string, ta
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMountRefs finds all other references to the device referenced
|
||||||
|
// by mountPath; returns a list of paths.
|
||||||
|
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
||||||
|
mps, err := mounter.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Find the device name.
|
||||||
|
deviceName := ""
|
||||||
|
// If mountPath is symlink, need get its target path.
|
||||||
|
slTarget, err := filepath.EvalSymlinks(mountPath)
|
||||||
|
if err != nil {
|
||||||
|
slTarget = mountPath
|
||||||
|
}
|
||||||
|
for i := range mps {
|
||||||
|
if mps[i].Path == slTarget {
|
||||||
|
deviceName = mps[i].Device
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all references to the device.
|
||||||
|
var refs []string
|
||||||
|
if deviceName == "" {
|
||||||
|
glog.Warningf("could not determine device for path: %q", mountPath)
|
||||||
|
} else {
|
||||||
|
for i := range mps {
|
||||||
|
if mps[i].Device == deviceName && mps[i].Path != slTarget {
|
||||||
|
refs = append(refs, mps[i].Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// detectSystemd returns true if OS runs with systemd as init. When not sure
|
// detectSystemd returns true if OS runs with systemd as init. When not sure
|
||||||
// (permission errors, ...), it returns false.
|
// (permission errors, ...), it returns false.
|
||||||
// There may be different ways how to detect systemd, this one makes sure that
|
// There may be different ways how to detect systemd, this one makes sure that
|
||||||
@ -299,6 +336,34 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
|
|||||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDeviceNameFromMount find the device name from /proc/mounts in which
|
||||||
|
// the mount path reference should match the given plugin directory. In case no mount path reference
|
||||||
|
// matches, returns the volume name taken from its given mountPath
|
||||||
|
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||||
|
refs, err := GetMountRefs(mounter, mountPath)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(refs) == 0 {
|
||||||
|
glog.V(4).Infof("Directory %s is not mounted", mountPath)
|
||||||
|
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||||
|
}
|
||||||
|
basemountPath := path.Join(pluginDir, MountsInGlobalPDPath)
|
||||||
|
for _, ref := range refs {
|
||||||
|
if strings.HasPrefix(ref, basemountPath) {
|
||||||
|
volumeID, err := filepath.Rel(basemountPath, ref)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return volumeID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Base(mountPath), nil
|
||||||
|
}
|
||||||
|
|
||||||
func listProcMounts(mountFilePath string) ([]MountPoint, error) {
|
func listProcMounts(mountFilePath string) ([]MountPoint, error) {
|
||||||
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
content, err := utilio.ConsistentRead(mountFilePath, maxListTries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -43,6 +43,12 @@ func (mounter *Mounter) Unmount(target string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMountRefs finds all other references to the device referenced
|
||||||
|
// by mountPath; returns a list of paths.
|
||||||
|
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mounter *Mounter) List() ([]MountPoint, error) {
|
func (mounter *Mounter) List() ([]MountPoint, error) {
|
||||||
return []MountPoint{}, nil
|
return []MountPoint{}, nil
|
||||||
}
|
}
|
||||||
@ -63,6 +69,10 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -118,6 +119,16 @@ func (mounter *Mounter) Unmount(target string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMountRefs finds all other references to the device(drive) referenced
|
||||||
|
// by mountPath; returns a list of paths.
|
||||||
|
func GetMountRefs(mounter Interface, mountPath string) ([]string, error) {
|
||||||
|
refs, err := getAllParentLinks(normalizeWindowsPath(mountPath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return refs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// List returns a list of all mounted filesystems. todo
|
// List returns a list of all mounted filesystems. todo
|
||||||
func (mounter *Mounter) List() ([]MountPoint, error) {
|
func (mounter *Mounter) List() ([]MountPoint, error) {
|
||||||
return []MountPoint{}, nil
|
return []MountPoint{}, nil
|
||||||
@ -152,6 +163,33 @@ func (mounter *Mounter) GetDeviceNameFromMount(mountPath, pluginDir string) (str
|
|||||||
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
return getDeviceNameFromMount(mounter, mountPath, pluginDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getDeviceNameFromMount find the device(drive) name in which
|
||||||
|
// the mount path reference should match the given plugin directory. In case no mount path reference
|
||||||
|
// matches, returns the volume name taken from its given mountPath
|
||||||
|
func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (string, error) {
|
||||||
|
refs, err := GetMountRefs(mounter, mountPath)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("GetMountRefs failed for mount path %q: %v", mountPath, err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(refs) == 0 {
|
||||||
|
return "", fmt.Errorf("directory %s is not mounted", mountPath)
|
||||||
|
}
|
||||||
|
basemountPath := normalizeWindowsPath(path.Join(pluginDir, MountsInGlobalPDPath))
|
||||||
|
for _, ref := range refs {
|
||||||
|
if strings.Contains(ref, basemountPath) {
|
||||||
|
volumeID, err := filepath.Rel(normalizeWindowsPath(basemountPath), ref)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Failed to get volume id from mount %s - %v", mountPath, err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return volumeID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.Base(mountPath), nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeviceOpened determines if the device is in use elsewhere
|
// DeviceOpened determines if the device is in use elsewhere
|
||||||
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
func (mounter *Mounter) DeviceOpened(pathname string) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -300,3 +338,30 @@ func getDriveLetterByDiskNumber(diskNum string, exec Exec) (string, error) {
|
|||||||
}
|
}
|
||||||
return string(output)[:1], nil
|
return string(output)[:1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getAllParentLinks walks all symbolic links and return all the parent targets recursively
|
||||||
|
func getAllParentLinks(path string) ([]string, error) {
|
||||||
|
const maxIter = 255
|
||||||
|
links := []string{}
|
||||||
|
for {
|
||||||
|
links = append(links, path)
|
||||||
|
if len(links) > maxIter {
|
||||||
|
return links, fmt.Errorf("unexpected length of parent links: %v", links)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return links, fmt.Errorf("Lstat: %v", err)
|
||||||
|
}
|
||||||
|
if fi.Mode()&os.ModeSymlink == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
path, err = os.Readlink(path)
|
||||||
|
if err != nil {
|
||||||
|
return links, fmt.Errorf("Readlink error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links, nil
|
||||||
|
}
|
||||||
|
@ -19,6 +19,8 @@ limitations under the License.
|
|||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,3 +71,70 @@ func TestValidateDiskNumber(t *testing.T) {
|
|||||||
t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
|
t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeLink(link, target string) error {
|
||||||
|
if output, err := exec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("mklink failed: %v, link(%q) target(%q) output: %q", err, link, target, string(output))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeLink(link string) error {
|
||||||
|
if output, err := exec.Command("cmd", "/c", "rmdir", link).CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("rmdir failed: %v, output: %q", err, string(output))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setEquivalent(set1, set2 []string) bool {
|
||||||
|
map1 := make(map[string]bool)
|
||||||
|
map2 := make(map[string]bool)
|
||||||
|
for _, s := range set1 {
|
||||||
|
map1[s] = true
|
||||||
|
}
|
||||||
|
for _, s := range set2 {
|
||||||
|
map2[s] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for s := range map1 {
|
||||||
|
if !map2[s] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s := range map2 {
|
||||||
|
if !map1[s] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// this func must run in admin mode, otherwise it will fail
|
||||||
|
func TestGetMountRefs(t *testing.T) {
|
||||||
|
fm := &FakeMounter{MountPoints: []MountPoint{}}
|
||||||
|
mountPath := `c:\secondmountpath`
|
||||||
|
expectedRefs := []string{`c:\`, `c:\firstmountpath`, mountPath}
|
||||||
|
|
||||||
|
// remove symbolic links first
|
||||||
|
for i := 1; i < len(expectedRefs); i++ {
|
||||||
|
removeLink(expectedRefs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// create symbolic links
|
||||||
|
for i := 1; i < len(expectedRefs); i++ {
|
||||||
|
if err := makeLink(expectedRefs[i], expectedRefs[i-1]); err != nil {
|
||||||
|
t.Errorf("makeLink failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if refs, err := GetMountRefs(fm, mountPath); err != nil || !setEquivalent(expectedRefs, refs) {
|
||||||
|
t.Errorf("getMountRefs(%q) = %v, error: %v; expected %v", mountPath, refs, err, expectedRefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove symbolic links
|
||||||
|
for i := 1; i < len(expectedRefs); i++ {
|
||||||
|
if err := removeLink(expectedRefs[i]); err != nil {
|
||||||
|
t.Errorf("removeLink failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user