Run fsck before formatting disk

Signed-off-by: Sami Wagiaalla <swagiaal@redhat.com>
This commit is contained in:
Sami Wagiaalla 2015-09-18 17:25:22 -04:00
parent 9e896e3416
commit 10688f1a11
2 changed files with 87 additions and 30 deletions

View File

@ -30,6 +30,7 @@ import (
"syscall" "syscall"
"github.com/golang/glog" "github.com/golang/glog"
utilExec "k8s.io/kubernetes/pkg/util/exec"
) )
const ( const (
@ -240,13 +241,31 @@ func readProcMountsFrom(file io.Reader, out *[]MountPoint) (uint32, error) {
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error { func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
options = append(options, "defaults") options = append(options, "defaults")
// Run fsck on the disk to fix repairable issues
args := []string{"-a", source}
cmd := mounter.Runner.Command("fsck", args...)
out, err := cmd.CombinedOutput()
if err != nil {
ee, isExitError := err.(utilExec.ExitError)
switch {
case err == utilExec.ErrExecutableNotFound:
glog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.")
case isExitError && ee.ExitStatus() == 1:
glog.Infof("Device %s has errors which were corrected by fsck.", source)
case isExitError && ee.ExitStatus() == 4:
return fmt.Errorf("'fsck' found errors on device %s but could not correct them: %s.", source, string(out))
case isExitError && ee.ExitStatus() > 4:
glog.Infof("`fsck` error %s", string(out))
}
}
// Try to mount the disk // Try to mount the disk
err := mounter.Interface.Mount(source, target, fstype, options) err = mounter.Interface.Mount(source, target, fstype, options)
if err != nil { if err != nil {
// It is possible that this disk is not formatted. Double check using diskLooksUnformatted // It is possible that this disk is not formatted. Double check using diskLooksUnformatted
notFormatted, err := mounter.diskLooksUnformatted(source) notFormatted, err := mounter.diskLooksUnformatted(source)
if err == nil && notFormatted { if err == nil && notFormatted {
args := []string{source} args = []string{source}
// Disk is unformatted so format it. // Disk is unformatted so format it.
// Use 'ext4' as the default // Use 'ext4' as the default
if len(fstype) == 0 { if len(fstype) == 0 {

View File

@ -47,69 +47,107 @@ type ExecArgs struct {
func TestSafeFormatAndMount(t *testing.T) { func TestSafeFormatAndMount(t *testing.T) {
tests := []struct { tests := []struct {
description string
fstype string fstype string
mountOptions []string mountOptions []string
execScripts []ExecArgs execScripts []ExecArgs
mountErrs []error mountErrs []error
expectedError error expectedError error
}{ }{
{ // Test a read only mount {
description: "Test a read only mount",
fstype: "ext4", fstype: "ext4",
mountOptions: []string{"ro"}, mountOptions: []string{"ro"},
}, },
{ // Test a normal mount {
fstype: "ext4", description: "Test a normal mount",
}, fstype: "ext4",
{ // Test that 'lsblk' is called and fails
fstype: "ext4",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
},
},
{
description: "Test 'fsck' fails with exit status 4",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &exec.FakeExitError{Status: 4}},
},
expectedError: fmt.Errorf("'fsck' found errors on device /dev/foo but could not correct them: ."),
},
{
description: "Test 'fsck' fails with exit status 1 (errors found and corrected)",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &exec.FakeExitError{Status: 1}},
},
},
{
description: "Test 'fsck' fails with exit status other than 1 and 4 (likely unformatted device)",
fstype: "ext4",
execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", &exec.FakeExitError{Status: 8}},
},
},
{
description: "Test that 'lsblk' is called and fails",
fstype: "ext4",
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{"-nd", "-o", "FSTYPE", "/dev/foo"}, "ext4", nil},
}, },
expectedError: fmt.Errorf("unknown filesystem type '(null)'"), expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
}, },
{ // Test that 'lsblk' is called and confirms unformatted disk, format fails {
fstype: "ext4", description: "Test that 'lsblk' is called and confirms unformatted disk, format fails",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")}, fstype: "ext4",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
}, },
expectedError: fmt.Errorf("formatting failed"), expectedError: fmt.Errorf("formatting failed"),
}, },
{ // Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount fails {
fstype: "ext4", description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount fails",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")}, fstype: "ext4",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), fmt.Errorf("Still cannot mount")},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil},
}, },
expectedError: fmt.Errorf("Still cannot mount"), expectedError: fmt.Errorf("Still cannot mount"),
}, },
{ // Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes {
fstype: "ext4", description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, fstype: "ext4",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, {"mkfs.ext4", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
}, },
{ // Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes with ext3 {
fstype: "ext3", description: "Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes with ext3",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil}, fstype: "ext3",
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
execScripts: []ExecArgs{ execScripts: []ExecArgs{
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"mkfs.ext3", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil}, {"mkfs.ext3", []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", "/dev/foo"}, "", nil},
}, },
expectedError: nil, expectedError: nil,
}, },
{ // Test that 'lsblk' is called and confirms unformatted disk, format passes, second mount passes {
// test that none ext4 fs does not get called with ext4 options. description: "test that none ext4 fs does not get called with ext4 options.",
fstype: "xfs", fstype: "xfs",
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},
{"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil}, {"lsblk", []string{"-nd", "-o", "FSTYPE", "/dev/foo"}, "", nil},
{"mkfs.xfs", []string{"/dev/foo"}, "", nil}, {"mkfs.xfs", []string{"/dev/foo"}, "", nil},
}, },
@ -159,23 +197,23 @@ func TestSafeFormatAndMount(t *testing.T) {
err := mounter.FormatAndMount(device, dest, test.fstype, test.mountOptions) err := mounter.FormatAndMount(device, dest, test.fstype, test.mountOptions)
if test.expectedError == nil { if test.expectedError == nil {
if err != nil { if err != nil {
t.Errorf("unexpected non-error: %v", err) t.Errorf("test \"%s\" unexpected non-error: %v", test.description, err)
} }
// Check that something was mounted on the directory // Check that something was mounted on the directory
isNotMountPoint, err := fakeMounter.IsLikelyNotMountPoint(dest) isNotMountPoint, err := fakeMounter.IsLikelyNotMountPoint(dest)
if err != nil || isNotMountPoint { if err != nil || isNotMountPoint {
t.Errorf("the directory was not mounted") t.Errorf("test \"%s\" the directory was not mounted", test.description)
} }
//check that the correct device was mounted //check that the correct device was mounted
mountedDevice, _, err := GetDeviceNameFromMount(fakeMounter.FakeMounter, dest) mountedDevice, _, err := GetDeviceNameFromMount(fakeMounter.FakeMounter, dest)
if err != nil || mountedDevice != device { if err != nil || mountedDevice != device {
t.Errorf("the correct device was not mounted") t.Errorf("test \"%s\" the correct device was not mounted", test.description)
} }
} else { } else {
if err == nil || test.expectedError.Error() != err.Error() { if err == nil || test.expectedError.Error() != err.Error() {
t.Errorf("unexpected error: %v. Expecting %v", err, test.expectedError) t.Errorf("test \"%s\" unexpected error: \n [%v]. \nExpecting [%v]", test.description, err, test.expectedError)
} }
} }
} }