Skip to content

Commit

Permalink
feature: update blkio device's read/write Bps/IOps
Browse files Browse the repository at this point in the history
fixes AliyunContainerService#2509

Signed-off-by: Leno Hou <lenohou@gmail.com>
  • Loading branch information
houstar committed Dec 18, 2018
1 parent 9e879af commit d248068
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 11 deletions.
2 changes: 1 addition & 1 deletion apis/types/resources.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 16 additions & 8 deletions cli/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func (uc *UpdateCommand) addFlags() {
flagSet.StringSliceVarP(&uc.labels, "label", "l", nil, "Set label for container")
flagSet.StringVar(&uc.restartPolicy, "restart", "", "Restart policy to apply when container exits")
flagSet.StringSliceVar(&uc.diskQuota, "disk-quota", nil, "Update disk quota for container(/=10g)")
flagSet.Var(&uc.blkioDeviceReadBps, "device-read-bps", "Update read rate (bytes per second) from a device")
flagSet.Var(&uc.blkioDeviceWriteBps, "device-write-bps", "Update write rate (bytes per second) from a device")
flagSet.Var(&uc.blkioDeviceReadIOps, "device-read-iops", "Update read rate (io per second) from a device")
flagSet.Var(&uc.blkioDeviceWriteIOps, "device-write-iops", "Update write rate (io per second) from a device")
}

// updateRun is the entry of update command.
Expand All @@ -69,14 +73,18 @@ func (uc *UpdateCommand) updateRun(args []string) error {
}

resource := types.Resources{
CPUPeriod: uc.cpuperiod,
CPUShares: uc.cpushare,
CPUQuota: uc.cpuquota,
CpusetCpus: uc.cpusetcpus,
CpusetMems: uc.cpusetmems,
Memory: memory,
MemorySwap: memorySwap,
BlkioWeight: uc.blkioWeight,
CPUPeriod: uc.cpuperiod,
CPUShares: uc.cpushare,
CPUQuota: uc.cpuquota,
CpusetCpus: uc.cpusetcpus,
CpusetMems: uc.cpusetmems,
Memory: memory,
MemorySwap: memorySwap,
BlkioWeight: uc.blkioWeight,
BlkioDeviceReadBps: uc.blkioDeviceReadBps.Value(),
BlkioDeviceWriteBps: uc.blkioDeviceWriteBps.Value(),
BlkioDeviceReadIOps: uc.blkioDeviceReadIOps.Value(),
BlkioDeviceWriteIOps: uc.blkioDeviceWriteIOps.Value(),
}

restartPolicy, err := opts.ParseRestartPolicy(uc.restartPolicy)
Expand Down
45 changes: 44 additions & 1 deletion ctrd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/tls"
"net"
"net/http"
"syscall"
"time"

"github.com/alibaba/pouch/apis/types"
Expand Down Expand Up @@ -76,13 +77,55 @@ func resolver(authConfig *types.AuthConfig) (remotes.Resolver, error) {
return docker.NewResolver(options), nil
}

// toLinuxThrottleDevice transfers Pouch ThrottleDeivce to Linux ThrottleDevice
func toLinuxThrottleDevice(devs []*types.ThrottleDevice) ([]specs.LinuxThrottleDevice, error) {
var stat syscall.Stat_t
var ThrottleDevice []specs.LinuxThrottleDevice

for _, dev := range devs {
if err := syscall.Stat(dev.Path, &stat); err != nil {
return nil, err
}

d := specs.LinuxThrottleDevice{
Rate: dev.Rate,
}
d.Major = int64(stat.Rdev >> 8)
d.Minor = int64(stat.Rdev & 255)
ThrottleDevice = append(ThrottleDevice, d)
}

return ThrottleDevice, nil
}

// toLinuxResources transfers Pouch Resources to LinuxResources.
func toLinuxResources(resources types.Resources) (*specs.LinuxResources, error) {
r := &specs.LinuxResources{}

readBpsDevice, err := toLinuxThrottleDevice(resources.BlkioDeviceReadBps)
if err != nil {
return nil, err
}
writeBpsDevice, err := toLinuxThrottleDevice(resources.BlkioDeviceWriteBps)
if err != nil {
return nil, err
}
readIOpsDevice, err := toLinuxThrottleDevice(resources.BlkioDeviceReadIOps)
if err != nil {
return nil, err
}
writeIOpsDevice, err := toLinuxThrottleDevice(resources.BlkioDeviceWriteIOps)
if err != nil {
return nil, err
}

// toLinuxBlockIO
r.BlockIO = &specs.LinuxBlockIO{
Weight: &resources.BlkioWeight,
Weight: &resources.BlkioWeight,
ThrottleReadBpsDevice: readBpsDevice,
ThrottleReadIOPSDevice: readIOpsDevice,
ThrottleWriteBpsDevice: writeBpsDevice,
ThrottleWriteIOPSDevice: writeIOpsDevice,
}

// toLinuxCPU
Expand Down
12 changes: 12 additions & 0 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,18 @@ func (mgr *ContainerManager) updateContainerResources(c *Container, resources ty
if resources.BlkioWeight != 0 {
cResources.BlkioWeight = resources.BlkioWeight
}
if resources.BlkioDeviceReadBps != nil {
cResources.BlkioDeviceReadBps = resources.BlkioDeviceReadBps
}
if resources.BlkioDeviceReadIOps != nil {
cResources.BlkioDeviceReadIOps = resources.BlkioDeviceReadIOps
}
if resources.BlkioDeviceWriteBps != nil {
cResources.BlkioDeviceWriteBps = resources.BlkioDeviceWriteBps
}
if resources.BlkioDeviceWriteIOps != nil {
cResources.BlkioDeviceWriteIOps = resources.BlkioDeviceWriteIOps
}
if resources.CPUPeriod != 0 {
cResources.CPUPeriod = resources.CPUPeriod
}
Expand Down
148 changes: 147 additions & 1 deletion test/cli_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/alibaba/pouch/pkg/utils"
"github.com/alibaba/pouch/test/command"
"github.com/alibaba/pouch/test/environment"
"github.com/alibaba/pouch/test/util"

"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
Expand Down Expand Up @@ -353,7 +355,7 @@ func (suite *PouchUpdateSuite) TestUpdateContainerDeleteEnv(c *check.C) {
}
}

// TestUpdateContainerDiskQuota is to verify the correctness of delete env by update interface
// TestUpdateContainerDiskQuota is to verify the correctness of disk quota by update interface
func (suite *PouchUpdateSuite) TestUpdateContainerDiskQuota(c *check.C) {
if !environment.IsDiskQuota() {
c.Skip("Host does not support disk quota")
Expand Down Expand Up @@ -395,3 +397,147 @@ func (suite *PouchUpdateSuite) TestUpdateContainerDiskQuota(c *check.C) {
}
c.Assert(found, check.Equals, true)
}

// TestUpdateWriteBps is to verify the correctness of update write bps
func (suite *PouchUpdateSuite) TestUpdateWriteBps(c *check.C) {
cname := "TestUpdateWriteBps"
testDisk := "/dev/null"

number, exist := util.GetMajMinNumOfDevice(testDisk)
if !exist {
c.Skip("fail to get major:minor device number")
}

oldLimitSpeed := "100"
newLimitSpeed := "300"
blkioDeviceWriteBpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.write_bps_device"
oldThrottleDev := testDisk + ":" + oldLimitSpeed
newThrottleDev := testDisk + ":" + newLimitSpeed
expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed)

res := command.PouchRun("run", "-d", "--name", cname,
"--device-write-bps ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, cname)

// update write bps
command.PouchRun("update", "--device-write-bps", newThrottleDev, cname).Assert(c, icmd.Success)

// restart container to update the configuration since runc don't support
// update device write bps
command.PouchRun("restart", cname).Assert(c, icmd.Success)

res = command.PouchRun("exec", cname, "cat", blkioDeviceWriteBpsFile)
res.Assert(c, icmd.Success)

out := res.Stdout()
c.Assert(out, check.Equals, expected)

}

// TestUpdateReadBps is to verify the correctness of update read bps
func (suite *PouchUpdateSuite) TestUpdateReadBps(c *check.C) {
cname := "TestUpdateReadBps"
testDisk := "/dev/null"

number, exist := util.GetMajMinNumOfDevice(testDisk)
if !exist {
c.Skip("fail to get major:minor device number")
}

oldLimitSpeed := "100"
newLimitSpeed := "300"
blkioDeviceReadBpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"
oldThrottleDev := testDisk + ":" + oldLimitSpeed
newThrottleDev := testDisk + ":" + newLimitSpeed
expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed)

res := command.PouchRun("run", "-d", "--name", cname,
"--device-read-bps ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, cname)

// update write bps
command.PouchRun("update", "--device-read-bps", newThrottleDev, cname).Assert(c, icmd.Success)

// restart container to update the configuration since runc don't support
// update device write bps
command.PouchRun("restart", cname).Assert(c, icmd.Success)

res = command.PouchRun("exec", cname, "cat", blkioDeviceReadBpsFile)
res.Assert(c, icmd.Success)

out := res.Stdout()
c.Assert(out, check.Equals, expected)

}

// TestUpdateWriteIOps is to verify the correctness of update write iops
func (suite *PouchUpdateSuite) TestUpdateWriteIOps(c *check.C) {
cname := "TestUpdateWriteIOps"
testDisk := "/dev/null"

number, exist := util.GetMajMinNumOfDevice(testDisk)
if !exist {
c.Skip("fail to get major:minor device number")
}

oldLimitSpeed := "100"
newLimitSpeed := "300"
blkioDeviceWriteIOpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.write_iops_device"
oldThrottleDev := testDisk + ":" + oldLimitSpeed
newThrottleDev := testDisk + ":" + newLimitSpeed
expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed)

res := command.PouchRun("run", "-d", "--name", cname,
"--device-write-iops ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, cname)

// update write bps
command.PouchRun("update", "--device-write-iops", newThrottleDev, cname).Assert(c, icmd.Success)

// restart container to update the configuration since runc don't support
// update device write bps
command.PouchRun("restart", cname).Assert(c, icmd.Success)

res = command.PouchRun("exec", cname, "cat", blkioDeviceWriteIOpsFile)
res.Assert(c, icmd.Success)

out := res.Stdout()
c.Assert(out, check.Equals, expected)

}

// TestUpdateReadIOps is to verify the correctness of update read iops
func (suite *PouchUpdateSuite) TestUpdateReadIOps(c *check.C) {
cname := "TestUpdateReadIOps"
testDisk := "/dev/null"

number, exist := util.GetMajMinNumOfDevice(testDisk)
if !exist {
c.Skip("fail to get major:minor device number")
}

oldLimitSpeed := "100"
newLimitSpeed := "300"
blkioDeviceReadIOpsFile := "/sys/fs/cgroup/blkio/blkio.throttle.read_iops_device"
oldThrottleDev := testDisk + ":" + oldLimitSpeed
newThrottleDev := testDisk + ":" + newLimitSpeed
expected := fmt.Sprintf("%s %s\n", number, newLimitSpeed)

res := command.PouchRun("run", "-d", "--name", cname,
"--device-read-iops ", oldThrottleDev, busyboxImage, "top").Assert(c, icmd.Success)
defer DelContainerForceMultyTime(c, cname)

// update write bps
command.PouchRun("update", "--device-read-iops", newThrottleDev, cname).Assert(c, icmd.Success)

// restart container to update the configuration since runc don't support
// update device write bps
command.PouchRun("restart", cname).Assert(c, icmd.Success)

res = command.PouchRun("exec", cname, "cat", blkioDeviceReadIOpsFile)
res.Assert(c, icmd.Success)

out := res.Stdout()
c.Assert(out, check.Equals, expected)

}

0 comments on commit d248068

Please sign in to comment.