Skip to content

Commit

Permalink
feature: support update container's cpu-period
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Wan <zirenwan@gmail.com>
  • Loading branch information
HusterWan committed Apr 26, 2018
1 parent dce981e commit f089431
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 24 deletions.
2 changes: 2 additions & 0 deletions cli/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func (uc *UpdateCommand) addFlags() {
flagSet := uc.cmd.Flags()
flagSet.SetInterspersed(false)
flagSet.Uint16Var(&uc.blkioWeight, "blkio-weight", 0, "Block IO (relative weight), between 10 and 1000, or 0 to disable")
flagSet.Int64Var(&uc.cpuperiod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period, range is in [1000(1ms),1000000(1s)]")
flagSet.Int64Var(&uc.cpushare, "cpu-share", 0, "CPU shares (relative weight)")
flagSet.StringVar(&uc.cpusetcpus, "cpuset-cpus", "", "CPUs in cpuset")
flagSet.StringVar(&uc.cpusetmems, "cpuset-mems", "", "MEMs in cpuset")
Expand Down Expand Up @@ -77,6 +78,7 @@ func (uc *UpdateCommand) updateRun(args []string) error {
}

resource := types.Resources{
CPUPeriod: uc.cpuperiod,
CPUShares: uc.cpushare,
CpusetCpus: uc.cpusetcpus,
CpusetMems: uc.cpusetmems,
Expand Down
10 changes: 7 additions & 3 deletions ctrd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,13 @@ func toLinuxResources(resources types.Resources) (*specs.LinuxResources, error)

// toLinuxCPU
shares := uint64(resources.CPUShares)
period := uint64(resources.CPUPeriod)
r.CPU = &specs.LinuxCPU{
Cpus: resources.CpusetCpus,
Mems: resources.CpusetMems,
Shares: &shares,
Period: &period,
Quota: &resources.CPUQuota,
}

// toLinuxMemory
Expand All @@ -158,9 +161,10 @@ func toLinuxResources(resources types.Resources) (*specs.LinuxResources, error)
swappiness = uint64(*(resources.MemorySwappiness))
}
r.Memory = &specs.LinuxMemory{
Limit: &resources.Memory,
Swap: &resources.MemorySwap,
Swappiness: &swappiness,
Limit: &resources.Memory,
Swap: &resources.MemorySwap,
Swappiness: &swappiness,
Reservation: &resources.MemoryReservation,
}

// TODO: add more fields.
Expand Down
75 changes: 54 additions & 21 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,10 @@ func (mgr *ContainerManager) Update(ctx context.Context, name string, config *ty
c.Lock()
defer c.Unlock()

if c.IsRunning() && config.Resources.KernelMemory != 0 {
return fmt.Errorf("failed to update container %s: can not update kernel memory to a running container, please stop it first", c.ID())
}

if len(config.Labels) != 0 {
if c.meta.Config.Labels == nil {
c.meta.Config.Labels = map[string]string{}
Expand All @@ -887,29 +891,11 @@ func (mgr *ContainerManager) Update(ctx context.Context, name string, config *ty
}
}

// update resources of container.
resources := config.Resources
cResources := &c.meta.HostConfig.Resources
if resources.BlkioWeight != 0 {
cResources.BlkioWeight = resources.BlkioWeight
}
if resources.CPUShares != 0 {
cResources.CPUShares = resources.CPUShares
}
if resources.CpusetCpus != "" {
cResources.CpusetCpus = resources.CpusetCpus
}
if resources.CpusetMems != "" {
cResources.CpusetMems = resources.CpusetMems
}
if resources.Memory != 0 {
cResources.Memory = resources.Memory
}
if resources.MemorySwap != 0 {
cResources.MemorySwap = resources.MemorySwap
// update Resources of a container.
if err := mgr.updateContainerResources(c.meta, config.Resources); err != nil {
return fmt.Errorf("failed to update container %s resources: %v", c.ID(), err)
}

// update HostConfig of a container.
// TODO update restartpolicy when container is running.
if config.RestartPolicy.Name != "" {
c.meta.HostConfig.RestartPolicy = config.RestartPolicy
Expand Down Expand Up @@ -945,6 +931,53 @@ func (mgr *ContainerManager) Update(ctx context.Context, name string, config *ty
return updateErr
}

// updateContainerResources update container's resources parameters.
func (mgr *ContainerManager) updateContainerResources(c *ContainerMeta, resources types.Resources) error {
// update resources of container.
cResources := &c.HostConfig.Resources
if resources.BlkioWeight != 0 {
cResources.BlkioWeight = resources.BlkioWeight
}
if resources.CPUPeriod != 0 {
cResources.CPUPeriod = resources.CPUPeriod
}
if resources.CPUQuota != 0 {
cResources.CPUQuota = resources.CPUQuota
}
if resources.CPUShares != 0 {
cResources.CPUShares = resources.CPUShares
}
if resources.CpusetCpus != "" {
cResources.CpusetCpus = resources.CpusetCpus
}
if resources.CpusetMems != "" {
cResources.CpusetMems = resources.CpusetMems
}
if resources.Memory != 0 {
// if memory limit smaller than already set memoryswap limit and doesn't
// update the memoryswap limit, then error out.
if cResources.MemorySwap != 0 && resources.Memory > cResources.MemorySwap && resources.MemorySwap == 0 {
return fmt.Errorf("Memory limit should be smaller than already set memoryswap limit, update the memoryswap at the same time")
}
cResources.Memory = resources.Memory
}
if resources.MemorySwap != 0 {
cResources.MemorySwap = resources.MemorySwap
}

if resources.MemorySwap != 0 {
cResources.MemorySwap = resources.MemorySwap
}
if resources.MemoryReservation != 0 {
cResources.MemoryReservation = resources.MemoryReservation
}
if resources.KernelMemory != 0 {
cResources.KernelMemory = resources.KernelMemory
}

return nil
}

// updateContainerEnv update the container's envs in /etc/instanceInfo and /etc/profile.d/pouchenv.sh
// Env used by rich container.
func (mgr *ContainerManager) updateContainerEnv(containerEnvs []string, baseFs string) error {
Expand Down
40 changes: 40 additions & 0 deletions test/cli_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,46 @@ func (suite *PouchUpdateSuite) TestUpdateCpu(c *check.C) {
command.PouchRun("rm", "-f", name).Assert(c, icmd.Success)
}

// TestUpdateCpuPeriod is to verify the correctness of updating container cpu-period.
func (suite *PouchUpdateSuite) TestUpdateCpuPeriod(c *check.C) {
name := "update-container-cpu-period"

command.PouchRun("run", "-d", "--name", name, busyboxImage, "top").Assert(c, icmd.Success)

output := command.PouchRun("inspect", name).Stdout()
result := []types.ContainerJSON{}
if err := json.Unmarshal([]byte(output), &result); err != nil {
c.Errorf("failed to decode inspect output: %v", err)
}
containerID := result[0].ID

file := "/sys/fs/cgroup/cpu/default/" + containerID + "/cpu.cfs_period_us"
if _, err := os.Stat(file); err != nil {
c.Fatalf("container %s cgroup mountpoint not exists", containerID)
}

command.PouchRun("update", "--cpu-period", "2000", name).Assert(c, icmd.Success)

out, err := exec.Command("cat", file).Output()
if err != nil {
c.Fatalf("execute cat command failed: %v", err)
}

if !strings.Contains(string(out), "2000") {
c.Fatalf("unexpected output %s expected %s\n", string(out), "2000")
}

inspectInfo := command.PouchRun("inspect", name).Stdout()
metaJSON := []types.ContainerJSON{}
if err := json.Unmarshal([]byte(inspectInfo), &metaJSON); err != nil {
c.Errorf("failed to decode inspect output: %v", err)
}

c.Assert(metaJSON[0].HostConfig.CPUPeriod, check.Equals, int64(2000))

command.PouchRun("rm", "-f", name).Assert(c, icmd.Success)
}

// TestUpdateRunningContainer is to verify the correctness of updating a running container.
func (suite *PouchUpdateSuite) TestUpdateRunningContainer(c *check.C) {
name := "update-running-container"
Expand Down

0 comments on commit f089431

Please sign in to comment.