495 lines
15 KiB
Go
495 lines
15 KiB
Go
// +build linux
|
|
|
|
package fs
|
|
|
|
import (
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
)
|
|
|
|
const (
|
|
memoryStatContents = `cache 512
|
|
rss 1024`
|
|
memoryUsageContents = "2048\n"
|
|
memoryMaxUsageContents = "4096\n"
|
|
memoryFailcnt = "100\n"
|
|
memoryLimitContents = "8192\n"
|
|
)
|
|
|
|
func TestMemorySetMemory(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
memoryBefore = 314572800 // 300M
|
|
memoryAfter = 524288000 // 500M
|
|
reservationBefore = 209715200 // 200M
|
|
reservationAfter = 314572800 // 300M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
|
|
"memory.soft_limit_in_bytes": strconv.Itoa(reservationBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.Memory = memoryAfter
|
|
helper.CgroupData.config.Resources.MemoryReservation = reservationAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryAfter {
|
|
t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.")
|
|
}
|
|
|
|
value, err = getCgroupParamUint(helper.CgroupPath, "memory.soft_limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.soft_limit_in_bytes - %s", err)
|
|
}
|
|
if value != reservationAfter {
|
|
t.Fatal("Got the wrong value, set memory.soft_limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetMemoryswap(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
memoryswapBefore = 314572800 // 300M
|
|
memoryswapAfter = 524288000 // 500M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryswapAfter {
|
|
t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetNegativeMemoryswap(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
memoryBefore = 314572800 // 300M
|
|
memoryAfter = 524288000 // 500M
|
|
memoryswapBefore = 629145600 // 600M
|
|
memoryswapAfter = 629145600 // 600M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
|
|
"memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.Memory = memoryAfter
|
|
// Negative value means not change
|
|
helper.CgroupData.config.Resources.MemorySwap = -1
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryAfter {
|
|
t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.")
|
|
}
|
|
|
|
value, err = getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryswapAfter {
|
|
t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetMemoryLargerThanSwap(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
memoryBefore = 314572800 // 300M
|
|
memoryswapBefore = 524288000 // 500M
|
|
memoryAfter = 629145600 // 600M
|
|
memoryswapAfter = 838860800 // 800M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
|
|
"memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore),
|
|
// Set will call getMemoryData when memory and swap memory are
|
|
// both set, fake these fields so we don't get error.
|
|
"memory.usage_in_bytes": "0",
|
|
"memory.max_usage_in_bytes": "0",
|
|
"memory.failcnt": "0",
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.Memory = memoryAfter
|
|
helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryAfter {
|
|
t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.")
|
|
}
|
|
value, err = getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryswapAfter {
|
|
t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetSwapSmallerThanMemory(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
memoryBefore = 629145600 // 600M
|
|
memoryswapBefore = 838860800 // 800M
|
|
memoryAfter = 314572800 // 300M
|
|
memoryswapAfter = 524288000 // 500M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.limit_in_bytes": strconv.Itoa(memoryBefore),
|
|
"memory.memsw.limit_in_bytes": strconv.Itoa(memoryswapBefore),
|
|
// Set will call getMemoryData when memory and swap memory are
|
|
// both set, fake these fields so we don't get error.
|
|
"memory.usage_in_bytes": "0",
|
|
"memory.max_usage_in_bytes": "0",
|
|
"memory.failcnt": "0",
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.Memory = memoryAfter
|
|
helper.CgroupData.config.Resources.MemorySwap = memoryswapAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryAfter {
|
|
t.Fatal("Got the wrong value, set memory.limit_in_bytes failed.")
|
|
}
|
|
value, err = getCgroupParamUint(helper.CgroupPath, "memory.memsw.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.memsw.limit_in_bytes - %s", err)
|
|
}
|
|
if value != memoryswapAfter {
|
|
t.Fatal("Got the wrong value, set memory.memsw.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetKernelMemory(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
kernelMemoryBefore = 314572800 // 300M
|
|
kernelMemoryAfter = 524288000 // 500M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.kmem.limit_in_bytes": strconv.Itoa(kernelMemoryBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.KernelMemory = kernelMemoryAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.kmem.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.kmem.limit_in_bytes - %s", err)
|
|
}
|
|
if value != kernelMemoryAfter {
|
|
t.Fatal("Got the wrong value, set memory.kmem.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetKernelMemoryTCP(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
kernelMemoryTCPBefore = 314572800 // 300M
|
|
kernelMemoryTCPAfter = 524288000 // 500M
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.kmem.tcp.limit_in_bytes": strconv.Itoa(kernelMemoryTCPBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.KernelMemoryTCP = kernelMemoryTCPAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.kmem.tcp.limit_in_bytes")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.kmem.tcp.limit_in_bytes - %s", err)
|
|
}
|
|
if value != kernelMemoryTCPAfter {
|
|
t.Fatal("Got the wrong value, set memory.kmem.tcp.limit_in_bytes failed.")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetMemorySwappinessDefault(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
swappinessBefore := 60 //default is 60
|
|
swappinessAfter := int64(0)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.swappiness": strconv.Itoa(swappinessBefore),
|
|
})
|
|
|
|
helper.CgroupData.config.Resources.MemorySwappiness = &swappinessAfter
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.swappiness")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.swappiness - %s", err)
|
|
}
|
|
if int64(value) != swappinessAfter {
|
|
t.Fatalf("Got the wrong value (%d), set memory.swappiness = %d failed.", value, swappinessAfter)
|
|
}
|
|
}
|
|
|
|
func TestMemoryStats(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.failcnt": memoryFailcnt,
|
|
"memory.memsw.usage_in_bytes": memoryUsageContents,
|
|
"memory.memsw.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.memsw.failcnt": memoryFailcnt,
|
|
"memory.memsw.limit_in_bytes": memoryLimitContents,
|
|
"memory.kmem.usage_in_bytes": memoryUsageContents,
|
|
"memory.kmem.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.kmem.failcnt": memoryFailcnt,
|
|
"memory.kmem.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Limit: 8192}, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
|
|
expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats)
|
|
}
|
|
|
|
func TestMemoryStatsNoStatFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsNoUsageFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsNoMaxUsageFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsNoLimitInBytesFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsBadStatFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": "rss rss",
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsBadUsageFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": "bad",
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsBadMaxUsageFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.max_usage_in_bytes": "bad",
|
|
"memory.limit_in_bytes": memoryLimitContents,
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemoryStatsBadLimitInBytesFile(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.stat": memoryStatContents,
|
|
"memory.usage_in_bytes": memoryUsageContents,
|
|
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
|
"memory.limit_in_bytes": "bad",
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
actualStats := *cgroups.NewStats()
|
|
err := memory.GetStats(helper.CgroupPath, &actualStats)
|
|
if err == nil {
|
|
t.Fatal("Expected failure")
|
|
}
|
|
}
|
|
|
|
func TestMemorySetOomControl(t *testing.T) {
|
|
helper := NewCgroupTestUtil("memory", t)
|
|
defer helper.cleanup()
|
|
|
|
const (
|
|
oomKillDisable = 1 // disable oom killer, default is 0
|
|
)
|
|
|
|
helper.writeFileContents(map[string]string{
|
|
"memory.oom_control": strconv.Itoa(oomKillDisable),
|
|
})
|
|
|
|
memory := &MemoryGroup{}
|
|
if err := memory.Set(helper.CgroupPath, helper.CgroupData.config); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
value, err := getCgroupParamUint(helper.CgroupPath, "memory.oom_control")
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse memory.oom_control - %s", err)
|
|
}
|
|
|
|
if value != oomKillDisable {
|
|
t.Fatalf("Got the wrong value, set memory.oom_control failed.")
|
|
}
|
|
}
|