Skip resize if fs is readonly (#114325)

* skip resize if fs is readonly

* run formatter + add log line for early return case

* fix error
This commit is contained in:
Julianne DeMars 2022-12-16 03:26:27 -08:00 committed by GitHub
parent 4ee4d815ee
commit 94fd5bd553
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 7 deletions

View File

@ -28,6 +28,10 @@ import (
utilexec "k8s.io/utils/exec" utilexec "k8s.io/utils/exec"
) )
const (
blockDev = "blockdev"
)
// ResizeFs Provides support for resizing file systems // ResizeFs Provides support for resizing file systems
type ResizeFs struct { type ResizeFs struct {
exec utilexec.Interface exec utilexec.Interface
@ -104,6 +108,17 @@ func (resizefs *ResizeFs) btrfsResize(deviceMountPath string) (bool, error) {
} }
func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string) (bool, error) { func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string) (bool, error) {
// Do nothing if device is mounted as readonly
readonly, err := resizefs.getDeviceRO(devicePath)
if err != nil {
return false, err
}
if readonly {
klog.V(3).Infof("ResizeFs.needResize - no resize possible since filesystem %s is readonly", devicePath)
return false, nil
}
deviceSize, err := resizefs.getDeviceSize(devicePath) deviceSize, err := resizefs.getDeviceSize(devicePath)
if err != nil { if err != nil {
return false, err return false, err
@ -147,7 +162,7 @@ func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string)
return true, nil return true, nil
} }
func (resizefs *ResizeFs) getDeviceSize(devicePath string) (uint64, error) { func (resizefs *ResizeFs) getDeviceSize(devicePath string) (uint64, error) {
output, err := resizefs.exec.Command("blockdev", "--getsize64", devicePath).CombinedOutput() output, err := resizefs.exec.Command(blockDev, "--getsize64", devicePath).CombinedOutput()
outStr := strings.TrimSpace(string(output)) outStr := strings.TrimSpace(string(output))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to read size of device %s: %s: %s", devicePath, err, outStr) return 0, fmt.Errorf("failed to read size of device %s: %s: %s", devicePath, err, outStr)
@ -159,6 +174,22 @@ func (resizefs *ResizeFs) getDeviceSize(devicePath string) (uint64, error) {
return size, nil return size, nil
} }
func (resizefs *ResizeFs) getDeviceRO(devicePath string) (bool, error) {
output, err := resizefs.exec.Command(blockDev, "--getro", devicePath).CombinedOutput()
outStr := strings.TrimSpace(string(output))
if err != nil {
return false, fmt.Errorf("failed to get readonly bit from device %s: %s: %s", devicePath, err, outStr)
}
switch outStr {
case "0":
return false, nil
case "1":
return true, nil
default:
return false, fmt.Errorf("Failed readonly device check. Expected 1 or 0, got '%s'", outStr)
}
}
func (resizefs *ResizeFs) getExtSize(devicePath string) (uint64, uint64, error) { func (resizefs *ResizeFs) getExtSize(devicePath string) (uint64, uint64, error) {
output, err := resizefs.exec.Command("dumpe2fs", "-h", devicePath).CombinedOutput() output, err := resizefs.exec.Command("dumpe2fs", "-h", devicePath).CombinedOutput()
if err != nil { if err != nil {

View File

@ -20,9 +20,11 @@ limitations under the License.
package mount package mount
import ( import (
"fmt"
"testing"
"k8s.io/utils/exec" "k8s.io/utils/exec"
fakeexec "k8s.io/utils/exec/testing" fakeexec "k8s.io/utils/exec/testing"
"testing"
) )
func TestGetFileSystemSize(t *testing.T) { func TestGetFileSystemSize(t *testing.T) {
@ -496,16 +498,53 @@ func TestNeedResize(t *testing.T) {
name string name string
devicePath string devicePath string
deviceMountPath string deviceMountPath string
readonly string
deviceSize string deviceSize string
extSize string
cmdOutputFsType string cmdOutputFsType string
expectError bool expectError bool
expectResult bool expectResult bool
}{ }{
{
name: "True",
devicePath: "/dev/test1",
deviceMountPath: "/mnt/test1",
readonly: "0",
deviceSize: "2048",
cmdOutputFsType: "TYPE=ext3",
extSize: "20",
expectError: false,
expectResult: true,
},
{
name: "False - needed by size but fs is readonly",
devicePath: "/dev/test1",
deviceMountPath: "/mnt/test1",
readonly: "1",
deviceSize: "2048",
cmdOutputFsType: "TYPE=ext3",
extSize: "20",
expectError: false,
expectResult: false,
},
{
name: "False - Not needed by size",
devicePath: "/dev/test1",
deviceMountPath: "/mnt/test1",
readonly: "0",
deviceSize: "20",
cmdOutputFsType: "TYPE=ext3",
extSize: "2048",
expectError: false,
expectResult: false,
},
{ {
name: "False - Unsupported fs type", name: "False - Unsupported fs type",
devicePath: "/dev/test1", devicePath: "/dev/test1",
deviceMountPath: "/mnt/test1", deviceMountPath: "/mnt/test1",
readonly: "0",
deviceSize: "2048", deviceSize: "2048",
extSize: "1",
cmdOutputFsType: "TYPE=ntfs", cmdOutputFsType: "TYPE=ntfs",
expectError: true, expectError: true,
expectResult: false, expectResult: false,
@ -516,25 +555,31 @@ func TestNeedResize(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
fcmd := fakeexec.FakeCmd{ fcmd := fakeexec.FakeCmd{
CombinedOutputScript: []fakeexec.FakeAction{ CombinedOutputScript: []fakeexec.FakeAction{
func() ([]byte, []byte, error) { return []byte(test.readonly), nil, nil },
func() ([]byte, []byte, error) { return []byte(test.deviceSize), nil, nil }, func() ([]byte, []byte, error) { return []byte(test.deviceSize), nil, nil },
func() ([]byte, []byte, error) { return []byte(test.cmdOutputFsType), nil, nil }, func() ([]byte, []byte, error) { return []byte(test.cmdOutputFsType), nil, nil },
func() ([]byte, []byte, error) {
return []byte(fmt.Sprintf("block size: %s\nblock count: 1", test.extSize)), nil, nil
},
}, },
} }
fexec := fakeexec.FakeExec{ fexec := fakeexec.FakeExec{
CommandScript: []fakeexec.FakeCommandAction{ CommandScript: []fakeexec.FakeCommandAction{
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
}, },
} }
resizefs := ResizeFs{exec: &fexec} resizefs := ResizeFs{exec: &fexec}
needResize, err := resizefs.NeedResize(test.devicePath, test.deviceMountPath) needResize, err := resizefs.NeedResize(test.devicePath, test.deviceMountPath)
if needResize != test.expectResult {
t.Fatalf("Expect result is %v but got %v", test.expectResult, needResize)
}
if !test.expectError && err != nil { if !test.expectError && err != nil {
t.Fatalf("Expect no error but got %v", err) t.Fatalf("Expect no error but got %v", err)
} }
if needResize != test.expectResult {
t.Fatalf("Expect result is %v but got %v", test.expectResult, needResize)
}
}) })
} }
} }