diff --git a/pkg/util/mount/mount_linux.go b/pkg/util/mount/mount_linux.go index 71064f321e3..f5e168b5b95 100644 --- a/pkg/util/mount/mount_linux.go +++ b/pkg/util/mount/mount_linux.go @@ -536,36 +536,57 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, 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) { - 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...) + args := []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", disk} + glog.V(4).Infof("Attempting to determine if disk %q is formatted using blkid with args: (%v)", disk, args) + dataOut, err := mounter.Exec.Run("blkid", args...) output := string(dataOut) - glog.V(4).Infof("Output: %q", output) + glog.V(4).Infof("Output: %q, err: %v", output, err) 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) return "", err } - // Split lsblk output into lines. Unformatted devices should contain only - // "\n". Beware of "\n\n", that's a device with one empty partition. - output = strings.TrimSuffix(output, "\n") // Avoid last empty line + var fstype, pttype string + lines := strings.Split(output, "\n") - if lines[0] != "" { - // The device is formatted - return lines[0], nil + for _, l := range lines { + if len(l) <= 0 { + // 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 { - // The device is unformatted and has no dependent devices - return "", nil + if len(pttype) > 0 { + glog.V(4).Infof("Disk %s detected partition table type: %s", pttype) + // 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 - // and MD RAID are reported as FSTYPE and caught above). - return "unknown data, probably partitions", nil + return fstype, nil } // isShared returns true, if given path is on a mount point that has shared diff --git a/pkg/util/mount/safe_format_and_mount_test.go b/pkg/util/mount/safe_format_and_mount_test.go index a7e7cc29a23..20bfeb9f624 100644 --- a/pkg/util/mount/safe_format_and_mount_test.go +++ b/pkg/util/mount/safe_format_and_mount_test.go @@ -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", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, execScripts: []ExecArgs{ {"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)'"), }, { - 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", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, execScripts: []ExecArgs{ {"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")}, }, 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", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")}, execScripts: []ExecArgs{ {"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}, }, 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", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"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}, }, 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", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"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}, }, expectedError: nil, @@ -159,30 +159,31 @@ func TestSafeFormatAndMount(t *testing.T) { mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"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}, }, expectedError: nil, }, { - description: "Test that 'lsblk' is called and reports ext4 partition", + description: "Test that 'blkid' is called and reports ext4 partition", fstype: "ext3", mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, execScripts: []ExecArgs{ {"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)'"), }, { - description: "Test that 'lsblk' is called and reports empty partition", - fstype: "ext3", - mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, + description: "Test that 'blkid' is called but has some usage or other errors (an exit code of 4 is returned)", + fstype: "xfs", + mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, execScripts: []ExecArgs{ {"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"), }, }