Commit 4cf36b8b authored by Jan Safranek's avatar Jan Safranek

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. I checked that LVM, LUKS and MD RAID have their own FSTYPE in lsblk output, so it should be only a partition table that has empty FSTYPE. The main point of this patch is to run lsblk without "-n", i.e. print all dependent devices and check if they're there.
parent 47320fd3
...@@ -386,7 +386,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, ...@@ -386,7 +386,7 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
return mountErr return mountErr
} else { } else {
// Block device is formatted with unexpected filesystem, let the user know // 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, ...@@ -395,19 +395,33 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
// diskLooksUnformatted uses 'lsblk' to see if the given disk is unformated // diskLooksUnformatted uses 'lsblk' 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{"-nd", "-o", "FSTYPE", disk} args := []string{"-n", "-o", "FSTYPE", disk}
cmd := mounter.Runner.Command("lsblk", args...) 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) glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args)
dataOut, err := cmd.CombinedOutput() dataOut, err := cmd.CombinedOutput()
output := strings.TrimSpace(string(dataOut)) output := string(dataOut)
glog.V(4).Infof("Output: %q", output)
// TODO (#13212): check if this disk has partitions and return false, and
// an error if so.
if err != nil { if err != 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
} }
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) { ...@@ -98,7 +98,7 @@ func TestSafeFormatAndMount(t *testing.T) {
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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "ext4", nil}, {"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "ext4\n", nil},
}, },
expectedError: fmt.Errorf("unknown filesystem type '(null)'"), expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
}, },
...@@ -108,7 +108,7 @@ func TestSafeFormatAndMount(t *testing.T) { ...@@ -108,7 +108,7 @@ func TestSafeFormatAndMount(t *testing.T) {
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{"-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")}, {"mkfs.ext4", []string{"-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
}, },
expectedError: fmt.Errorf("formatting failed"), expectedError: fmt.Errorf("formatting failed"),
...@@ -119,7 +119,7 @@ func TestSafeFormatAndMount(t *testing.T) { ...@@ -119,7 +119,7 @@ func TestSafeFormatAndMount(t *testing.T) {
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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"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"),
...@@ -130,7 +130,7 @@ func TestSafeFormatAndMount(t *testing.T) { ...@@ -130,7 +130,7 @@ 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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil}, {"mkfs.ext4", []string{"-F", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
...@@ -141,7 +141,7 @@ func TestSafeFormatAndMount(t *testing.T) { ...@@ -141,7 +141,7 @@ 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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"mkfs.ext3", []string{"-F", "/dev/foo"}, "", nil}, {"mkfs.ext3", []string{"-F", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
...@@ -152,11 +152,31 @@ func TestSafeFormatAndMount(t *testing.T) { ...@@ -152,11 +152,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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-n", "-o", "FSTYPE", "/dev/foo"}, "\n", nil},
{"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",
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 { 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