Commit 1ed77078 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #43378 from jsafrane/fix-partition-mount

Automatic merge from submit-queue (batch tested with PRs 43378, 43216, 43384, 43083, 43428) Do not reformat devices with partitions `lsblk` reports FSTYPE of devices with partition tables as empty string `""`, which is indistinguishable from empty devices. We must look for dependent devices (i.e. partitions) to see that the device is really empty and report error otherwise. The main point of this patch is to run `lsblk` without `"-n"`, i.e. print all dependent devices and check it output. Sample output: ``` FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 10s 10s 1 default-scheduler Normal Scheduled Successfully assigned testpod to ip-172-18-11-149.ec2.internal 2s 2s 1 kubelet, ip-172-18-11-149.ec2.internal Warning FailedMount MountVolume.MountDevice failed for volume "kubernetes.io/aws-ebs/vol-0fa9da8b91913b187" (spec.Name: "vol") pod "b74f68c5-0d6a-11e7-9233-0e11251010c0" (UID: "b74f68c5-0d6a-11e7-9233-0e11251010c0") with: failed to mount the volume as "ext4", it already contains unknown data, probably partitions. Mount error: mount failed: exit status 32 Mounting command: mount Mounting arguments: /dev/xvdbb /var/lib/kubelet/plugins/kubernetes.io/aws-ebs/mounts/vol-0fa9da8b91913b187 ext4 [defaults] Output: mount: wrong fs type, bad option, bad superblock on /dev/xvdbb, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so. ``` Without this patch, the device would be reformatted and all data in the device partitions would be lost. Fixes #13212 Release note: ```release-note NONE ``` @kubernetes/sig-storage-pr-reviews
parents f4d863a6 4cf36b8b
......@@ -386,7 +386,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
return mountErr
} else {
// Block device is formatted with unexpected filesystem, let the user know
return fmt.Errorf("failed to mount the volume as %q, it's already formatted with %q. Mount error: %v", fstype, existingFormat, mountErr)
return fmt.Errorf("failed to mount the volume as %q, it already contains %s. Mount error: %v", fstype, existingFormat, mountErr)
}
}
}
......@@ -395,19 +395,33 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// diskLooksUnformatted uses 'lsblk' to see if the given disk is unformated
func (mounter *SafeFormatAndMount) getDiskFormat(disk string) (string, error) {
args := []string{"-nd", "-o", "FSTYPE", disk}
args := []string{"-n", "-o", "FSTYPE", disk}
cmd := mounter.Runner.Command("lsblk", args...)
glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args)
dataOut, err := cmd.CombinedOutput()
output := strings.TrimSpace(string(dataOut))
// TODO (#13212): check if this disk has partitions and return false, and
// an error if so.
output := string(dataOut)
glog.V(4).Infof("Output: %q", output)
if err != nil {
glog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err)
return "", err
}
return strings.TrimSpace(output), nil
// 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
lines := strings.Split(output, "\n")
if lines[0] != "" {
// The device is formatted
return lines[0], nil
}
if len(lines) == 1 {
// The device is unformatted and has no dependent devices
return "", 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
}
......@@ -98,7 +98,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "ext4", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "ext4\n", nil},
},
expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
},
......@@ -108,7 +108,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
},
expectedError: fmt.Errorf("formatting failed"),
......@@ -119,7 +119,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
},
expectedError: fmt.Errorf("Still cannot mount"),
......@@ -130,7 +130,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
},
expectedError: nil,
......@@ -141,7 +141,7 @@ func TestSafeFormatAndMount(t *testing.T) {
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext3", []string{"-F", "/dev/foo"}, "", nil},
},
expectedError: nil,
......@@ -152,11 +152,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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
},
expectedError: nil,
},
{
description: "Test that 'lsblk' 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},
},
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)'")},
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n\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)'"),
},
}
for _, test := range tests {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment