mirror of https://github.com/k3s-io/k3s
Merge pull request #59050 from cofyc/get_fstype
Automatic merge from submit-queue (batch tested with PRs 51323, 59306, 58991, 59050). 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>. Proposal: Use `blkid` to detect fs type of device instead of `lsblk`. **What this PR does / why we need it**: Use `blkid` to detect fs type of device instead of `lsblk`. `lsblk` depends on `udev`, and device driver's udev rules. If udev rules are not installed properly, `lsblk` could not get fs type of disk. This will cause problems, e.g. expanding volume will fail because it could not detect fs type of disk. Take `rbd` as example, `lsblk -n -o FSTYPE /dev/rbd0` command actually read fs type from `/run/udev/data/b252:0` (may vary on different machines, see real file from `strace lsblk -n -o FSTYPE /dev/rbd0` ). This file `/run/udev/data/b252:0` is generated by `udev` and device driver's udev files. If machine don't have `/lib/udev/rules.d/60-ceph-by-parttypeuuid.rules` udev rule file installed (this file is from `ceph-osd` package on ubuntu), it will not be properly generated, e.g: ``` # cat /run/udev/data/b251:0 S:rbd/<pool>/<image> I:13234059587579 E:ID_FS_TYPE= E:net.ifnames=0 G:systemd ``` `lsblk -n -o FSTYPE /dev/rbd0` will get empty fs type. [60-ceph-by-parttypeuuid.rules](https://github.com/ceph/ceph/blob/v13.0.0/udev/60-ceph-by-parttypeuuid.rules) is udev rule, which underlyingly runs `blkid` commands to get infos of device, then store them in udev file. If we use `blkid` to get fs type, kubelet volume manager will not depend on `udev` stuffs. Currently, if kubelet node does not have `60-ceph-by-parttypeuuid.rules` installed (from `ceph-osd` package), it will fail to get fs type of rbd image. Even administrator install `ceph-osd` later, it can not get fs type of previous mapped images (udev data files not be to updated automatically). **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes # **Special notes for your reviewer**: `udevadm test` logs: - Ubuntu 16.04 (ceph-common installed), without ceph-osd: [without-ceph-osd.log](https://github.com/kubernetes/kubernetes/files/1678512/without-ceph-osd.log) - Ubuntu 16.04 (ceph-common installed), with ceph-osd: [with-ceph-osd.log](https://github.com/kubernetes/kubernetes/files/1678509/with-ceph-osd.log) **Release note**: ```release-note NONE ```pull/6/head
commit
b13092554c
|
@ -536,36 +536,57 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
|
||||||
return mountErr
|
return mountErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiskFormat uses 'lsblk' to see if the given disk is unformated
|
// GetDiskFormat uses 'blkid' to see if the given disk is unformated
|
||||||
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
|
func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
|
||||||
args := []string{"-n", "-o", "FSTYPE", disk}
|
args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk}
|
||||||
glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args)
|
glog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args)
|
||||||
dataOut, err := mounter.Exec.Run("lsblk", args...)
|
dataOut, err := mounter.Exec.Run("blkid", args...)
|
||||||
output := string(dataOut)
|
output := string(dataOut)
|
||||||
glog.V(4).Infof("Output: %q", output)
|
glog.V(4).Infof("Output: %q, err: %v", output, err)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if exit, ok := err.(utilexec.ExitError); ok {
|
||||||
|
if exit.ExitStatus() == 2 {
|
||||||
|
// Disk device is unformatted.
|
||||||
|
// For `blkid`, if the specified token (TYPE/PTTYPE, etc) was
|
||||||
|
// not found, or no (specified) devices could be identified, an
|
||||||
|
// exit code of 2 is returned.
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
glog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err)
|
glog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split lsblk output into lines. Unformatted devices should contain only
|
var fstype, pttype string
|
||||||
// "\n". Beware of "\n\n", that's a device with one empty partition.
|
|
||||||
output = strings.TrimSuffix(output, "\n") // Avoid last empty line
|
|
||||||
lines := strings.Split(output, "\n")
|
lines := strings.Split(output, "\n")
|
||||||
if lines[0] != "" {
|
for _, l := range lines {
|
||||||
// The device is formatted
|
if len(l) <= 0 {
|
||||||
return lines[0], nil
|
// Ignore empty line.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cs := strings.Split(l, "=")
|
||||||
|
if len(cs) != 2 {
|
||||||
|
return "", fmt.Errorf("blkid returns invalid output: %s", output)
|
||||||
|
}
|
||||||
|
// TYPE is filesystem type, and PTTYPE is partition table type, according
|
||||||
|
// to https://www.kernel.org/pub/linux/utils/util-linux/v2.21/libblkid-docs/.
|
||||||
|
if cs[0] == "TYPE" {
|
||||||
|
fstype = cs[1]
|
||||||
|
} else if cs[0] == "PTTYPE" {
|
||||||
|
pttype = cs[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(lines) == 1 {
|
if len(pttype) > 0 {
|
||||||
// The device is unformatted and has no dependent devices
|
glog.V(4).Infof("Disk %s detected partition table type: %s", pttype)
|
||||||
return "", nil
|
// Returns a special non-empty string as filesystem type, then kubelet
|
||||||
|
// will not format it.
|
||||||
|
return "unknown data, probably partitions", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The device has dependent devices, most probably partitions (LVM, LUKS
|
return fstype, nil
|
||||||
// and MD RAID are reported as FSTYPE and caught above).
|
|
||||||
return "unknown data, probably partitions", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isShared returns true, if given path is on a mount point that has shared
|
// isShared returns true, if given path is on a mount point that has shared
|
||||||
|
|
|
@ -100,55 +100,55 @@ func TestSafeFormatAndMount(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and fails",
|
description: "Test that 'blkid' is called and fails",
|
||||||
fstype: "ext4",
|
fstype: "ext4",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "ext4\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
|
expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and confirms unformatted disk, format fails",
|
description: "Test that 'blkid' is called and confirms unformatted disk, format fails",
|
||||||
fstype: "ext4",
|
fstype: "ext4",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
|
||||||
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
|
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Errorf("formatting failed"),
|
expectedError: fmt.Errorf("formatting failed"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount fails",
|
description: "Test that 'blkid' is called and confirms unformatted disk, format passes, second mount fails",
|
||||||
fstype: "ext4",
|
fstype: "ext4",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
|
||||||
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
|
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Errorf("Still cannot mount"),
|
expectedError: fmt.Errorf("Still cannot mount"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes",
|
description: "Test that 'blkid' is called and confirms unformatted disk, format passes, second mount passes",
|
||||||
fstype: "ext4",
|
fstype: "ext4",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
|
||||||
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
|
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes with ext3",
|
description: "Test that 'blkid' is called and confirms unformatted disk, format passes, second mount passes with ext3",
|
||||||
fstype: "ext3",
|
fstype: "ext3",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
|
||||||
{"mkfs.ext3", []string{"-F", "/dev/foo"}, "", nil},
|
{"mkfs.ext3", []string{"-F", "/dev/foo"}, "", nil},
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
|
@ -159,30 +159,31 @@ func TestSafeFormatAndMount(t *testing.T) {
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 2}},
|
||||||
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
|
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
|
||||||
},
|
},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and reports ext4 partition",
|
description: "Test that 'blkid' is called and reports ext4 partition",
|
||||||
fstype: "ext3",
|
fstype: "ext3",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\next4\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nPTTYPE=dos\n", nil},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Errorf("failed to mount the volume as \"ext3\", it already contains unknown data, probably partitions. Mount error: unknown filesystem type '(null)'"),
|
expectedError: fmt.Errorf("failed to mount the volume as \"ext3\", it already contains unknown data, probably partitions. Mount error: unknown filesystem type '(null)'"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Test that 'lsblk' is called and reports empty partition",
|
description: "Test that 'blkid' is called but has some usage or other errors (an exit code of 4 is returned)",
|
||||||
fstype: "ext3",
|
fstype: "xfs",
|
||||||
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
|
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
|
||||||
execScripts: []ExecArgs{
|
execScripts: []ExecArgs{
|
||||||
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
|
||||||
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n\n", nil},
|
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &fakeexec.FakeExitError{Status: 4}},
|
||||||
|
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Errorf("failed to mount the volume as \"ext3\", it already contains unknown data, probably partitions. Mount error: unknown filesystem type '(null)'"),
|
expectedError: fmt.Errorf("exit 4"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue