empty_dir: Check if hugetlbfs volume is mounted with a correct pagesize
Extended GetMountMedium function to check if hugetlbfs volume is mounted with the page size equal to the medium size. Page size is obtained from the 'pagesize' mount option of the mounted hugetlbfs volume.
This commit is contained in:
@@ -19,6 +19,8 @@ limitations under the License.
|
||||
package emptydir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -73,8 +75,8 @@ type fakeMountDetector struct {
|
||||
isMount bool
|
||||
}
|
||||
|
||||
func (fake *fakeMountDetector) GetMountMedium(path string) (v1.StorageMedium, bool, error) {
|
||||
return fake.medium, fake.isMount, nil
|
||||
func (fake *fakeMountDetector) GetMountMedium(path string, requestedMedium v1.StorageMedium) (v1.StorageMedium, bool, *resource.Quantity, error) {
|
||||
return fake.medium, fake.isMount, nil, nil
|
||||
}
|
||||
|
||||
func TestPluginEmptyRootContext(t *testing.T) {
|
||||
@@ -582,3 +584,331 @@ func TestGetHugePagesMountOptions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testMountDetector struct {
|
||||
pageSize *resource.Quantity
|
||||
isMnt bool
|
||||
err error
|
||||
}
|
||||
|
||||
func (md *testMountDetector) GetMountMedium(path string, requestedMedium v1.StorageMedium) (v1.StorageMedium, bool, *resource.Quantity, error) {
|
||||
return v1.StorageMediumHugePages, md.isMnt, md.pageSize, md.err
|
||||
}
|
||||
|
||||
func TestSetupHugepages(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "TestSetupHugepages")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
pageSize2Mi := resource.MustParse("2Mi")
|
||||
|
||||
testCases := map[string]struct {
|
||||
path string
|
||||
ed *emptyDir
|
||||
shouldFail bool
|
||||
}{
|
||||
"Valid: mount expected": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: v1.StorageMediumHugePages,
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: &mount.FakeMounter{},
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: &resource.Quantity{},
|
||||
isMnt: false,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
"Valid: already mounted with correct pagesize": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages-2Mi",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: mount.NewFakeMounter([]mount.MountPoint{{Path: tmpdir, Opts: []string{"rw", "pagesize=2M", "realtime"}}}),
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: &pageSize2Mi,
|
||||
isMnt: true,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
"Valid: already mounted": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: mount.NewFakeMounter([]mount.MountPoint{{Path: tmpdir, Opts: []string{"rw", "pagesize=2M", "realtime"}}}),
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: nil,
|
||||
isMnt: true,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
shouldFail: false,
|
||||
},
|
||||
"Invalid: mounter is nil": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages-2Mi",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: nil,
|
||||
},
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid: GetMountMedium error": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages-2Mi",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: mount.NewFakeMounter([]mount.MountPoint{{Path: tmpdir, Opts: []string{"rw", "pagesize=2M", "realtime"}}}),
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: &pageSize2Mi,
|
||||
isMnt: true,
|
||||
err: fmt.Errorf("GetMountMedium error"),
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid: medium and page size differ": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages-1Gi",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: mount.NewFakeMounter([]mount.MountPoint{{Path: tmpdir, Opts: []string{"rw", "pagesize=2M", "realtime"}}}),
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: &pageSize2Mi,
|
||||
isMnt: true,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid medium": {
|
||||
path: tmpdir,
|
||||
ed: &emptyDir{
|
||||
medium: "HugePages-NN",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: &mount.FakeMounter{},
|
||||
mountDetector: &testMountDetector{
|
||||
pageSize: &resource.Quantity{},
|
||||
isMnt: false,
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid: setupDir fails": {
|
||||
path: "",
|
||||
ed: &emptyDir{
|
||||
medium: v1.StorageMediumHugePages,
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mounter: &mount.FakeMounter{},
|
||||
},
|
||||
shouldFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testCaseName, testCase := range testCases {
|
||||
t.Run(testCaseName, func(t *testing.T) {
|
||||
err := testCase.ed.setupHugepages(testCase.path)
|
||||
if testCase.shouldFail && err == nil {
|
||||
t.Errorf("%s: Unexpected success", testCaseName)
|
||||
} else if !testCase.shouldFail && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", testCaseName, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPageSize(t *testing.T) {
|
||||
mounter := &mount.FakeMounter{
|
||||
MountPoints: []mount.MountPoint{
|
||||
{
|
||||
Device: "/dev/sda2",
|
||||
Type: "ext4",
|
||||
Path: "/",
|
||||
Opts: []string{"rw", "relatime", "errors=remount-ro"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/hugepages",
|
||||
Type: "hugetlbfs",
|
||||
Path: "/mnt/hugepages-2Mi",
|
||||
Opts: []string{"rw", "relatime", "pagesize=2M"},
|
||||
},
|
||||
{
|
||||
Device: "sysfs",
|
||||
Type: "sysfs",
|
||||
Path: "/sys",
|
||||
Opts: []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/hugepages",
|
||||
Type: "hugetlbfs",
|
||||
Path: "/mnt/hugepages-1Gi",
|
||||
Opts: []string{"rw", "relatime", "pagesize=1024M"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/hugepages",
|
||||
Type: "hugetlbfs",
|
||||
Path: "/mnt/noopt",
|
||||
Opts: []string{"rw", "relatime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/hugepages",
|
||||
Type: "hugetlbfs",
|
||||
Path: "/mnt/badopt",
|
||||
Opts: []string{"rw", "relatime", "pagesize=NN"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
path string
|
||||
mounter mount.Interface
|
||||
expectedResult resource.Quantity
|
||||
shouldFail bool
|
||||
}{
|
||||
"Valid: existing 2Mi mount": {
|
||||
path: "/mnt/hugepages-2Mi",
|
||||
mounter: mounter,
|
||||
shouldFail: false,
|
||||
expectedResult: resource.MustParse("2Mi"),
|
||||
},
|
||||
"Valid: existing 1Gi mount": {
|
||||
path: "/mnt/hugepages-1Gi",
|
||||
mounter: mounter,
|
||||
shouldFail: false,
|
||||
expectedResult: resource.MustParse("1Gi"),
|
||||
},
|
||||
"Invalid: mount point doesn't exist": {
|
||||
path: "/mnt/nomp",
|
||||
mounter: mounter,
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid: no pagesize option": {
|
||||
path: "/mnt/noopt",
|
||||
mounter: mounter,
|
||||
shouldFail: true,
|
||||
},
|
||||
"Invalid: incorrect pagesize option": {
|
||||
path: "/mnt/badopt",
|
||||
mounter: mounter,
|
||||
shouldFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testCaseName, testCase := range testCases {
|
||||
t.Run(testCaseName, func(t *testing.T) {
|
||||
pageSize, err := getPageSize(testCase.path, testCase.mounter)
|
||||
if testCase.shouldFail && err == nil {
|
||||
t.Errorf("%s: Unexpected success", testCaseName)
|
||||
} else if !testCase.shouldFail && err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", testCaseName, err)
|
||||
}
|
||||
if err == nil && pageSize.Cmp(testCase.expectedResult) != 0 {
|
||||
t.Errorf("%s: Unexpected result: %s, expected: %s", testCaseName, pageSize.String(), testCase.expectedResult.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user