Skip to content

Commit

Permalink
implement podman update
Browse files Browse the repository at this point in the history
podman update allows users to change the cgroup configuration of an existing container using the already defined resource limits flags
from podman create/run. The supported flags in crun are:

–memory
–cpus
–cpuset-cpus
–cpuset-mems
–memory-swap
–memory-reservation
–cpu-shares
–cpu-quota
–cpu-period
–blkio-weight
–cpu-rt-period
–cpu-rt-runtime
-device-read-bps
-device-write-bps
-device-read-iops
-device-write-iops
-memory-swappiness
-blkio-weight-device

resolves containers#15067

Signed-off-by: Charlie Doern <cdoern@redhat.com>
  • Loading branch information
cdoern committed Aug 11, 2022
1 parent 89ab5c9 commit 5f757cb
Show file tree
Hide file tree
Showing 37 changed files with 578 additions and 150 deletions.
52 changes: 27 additions & 25 deletions cmd/podman/common/create.go
Expand Up @@ -28,10 +28,10 @@ func ContainerToPodOptions(containerCreate *entities.ContainerCreateOptions, pod
}

// DefineCreateFlags declares and instantiates the container create flags
func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool, clone bool) {
func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, mode entities.ContainerMode) {
createFlags := cmd.Flags()

if !isInfra && !clone { // regular create flags
if mode == entities.CreateMode { // regular create flags
annotationFlagName := "annotation"
createFlags.StringSliceVar(
&cf.Annotation,
Expand Down Expand Up @@ -103,22 +103,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(deviceCgroupRuleFlagName, completion.AutocompleteNone)

deviceReadIopsFlagName := "device-read-iops"
createFlags.StringSliceVar(
&cf.DeviceReadIOPs,
deviceReadIopsFlagName, []string{},
"Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)",
)
_ = cmd.RegisterFlagCompletionFunc(deviceReadIopsFlagName, completion.AutocompleteDefault)

deviceWriteIopsFlagName := "device-write-iops"
createFlags.StringSliceVar(
&cf.DeviceWriteIOPs,
deviceWriteIopsFlagName, []string{},
"Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
)
_ = cmd.RegisterFlagCompletionFunc(deviceWriteIopsFlagName, completion.AutocompleteDefault)

createFlags.Bool(
"disable-content-trust", false,
"This is a Docker specific option and is a NOOP",
Expand Down Expand Up @@ -589,7 +573,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
`If a container with the same name exists, replace it`,
)
}
if isInfra || (!clone && !isInfra) { // infra container flags, create should also pick these up
if mode == entities.InfraMode || (mode == entities.CreateMode) { // infra container flags, create should also pick these up
shmSizeFlagName := "shm-size"
createFlags.String(
shmSizeFlagName, shmSize(),
Expand Down Expand Up @@ -669,7 +653,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(cgroupParentFlagName, completion.AutocompleteDefault)
var conmonPidfileFlagName string
if !isInfra {
if mode == entities.CreateMode {
conmonPidfileFlagName = "conmon-pidfile"
} else {
conmonPidfileFlagName = "infra-conmon-pidfile"
Expand All @@ -682,7 +666,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
_ = cmd.RegisterFlagCompletionFunc(conmonPidfileFlagName, completion.AutocompleteDefault)

var entrypointFlagName string
if !isInfra {
if mode == entities.CreateMode {
entrypointFlagName = "entrypoint"
} else {
entrypointFlagName = "infra-command"
Expand Down Expand Up @@ -717,7 +701,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)

if isInfra {
if mode == entities.InfraMode {
nameFlagName := "infra-name"
createFlags.StringVar(
&cf.Name,
Expand Down Expand Up @@ -767,7 +751,8 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(volumesFromFlagName, AutocompleteContainers)
}
if clone || !isInfra { // clone and create only flags, we need this level of separation so clone does not pick up all of the flags

if mode == entities.CloneMode || mode == entities.CreateMode {
nameFlagName := "name"
createFlags.StringVar(
&cf.Name,
Expand All @@ -783,7 +768,8 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
"Run container in an existing pod",
)
_ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods)

}
if mode != entities.InfraMode { // clone create and update only flags, we need this level of separation so clone does not pick up all of the flags
cpuPeriodFlagName := "cpu-period"
createFlags.Uint64Var(
&cf.CPUPeriod,
Expand Down Expand Up @@ -832,8 +818,24 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(memorySwappinessFlagName, completion.AutocompleteNone)
}
// anyone can use these
if mode == entities.CreateMode || mode == entities.UpdateMode {
deviceReadIopsFlagName := "device-read-iops"
createFlags.StringSliceVar(
&cf.DeviceReadIOPs,
deviceReadIopsFlagName, []string{},
"Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)",
)
_ = cmd.RegisterFlagCompletionFunc(deviceReadIopsFlagName, completion.AutocompleteDefault)

deviceWriteIopsFlagName := "device-write-iops"
createFlags.StringSliceVar(
&cf.DeviceWriteIOPs,
deviceWriteIopsFlagName, []string{},
"Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
)
_ = cmd.RegisterFlagCompletionFunc(deviceWriteIopsFlagName, completion.AutocompleteDefault)
}
// anyone can use these
cpusFlagName := "cpus"
createFlags.Float64Var(
&cf.CPUS,
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/containers/clone.go
Expand Up @@ -41,7 +41,7 @@ func cloneFlags(cmd *cobra.Command) {
flags.BoolVarP(&ctrClone.Force, forceFlagName, "f", false, "force the existing container to be destroyed")

common.DefineCreateDefaults(&ctrClone.CreateOpts)
common.DefineCreateFlags(cmd, &ctrClone.CreateOpts, false, true)
common.DefineCreateFlags(cmd, &ctrClone.CreateOpts, entities.CloneMode)
}
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/containers/create.go
Expand Up @@ -72,7 +72,7 @@ func createFlags(cmd *cobra.Command) {

flags.SetInterspersed(false)
common.DefineCreateDefaults(&cliVals)
common.DefineCreateFlags(cmd, &cliVals, false, false)
common.DefineCreateFlags(cmd, &cliVals, entities.CreateMode)
common.DefineNetFlags(cmd)

flags.SetNormalizeFunc(utils.AliasFlags)
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/containers/run.go
Expand Up @@ -61,7 +61,7 @@ func runFlags(cmd *cobra.Command) {

flags.SetInterspersed(false)
common.DefineCreateDefaults(&cliVals)
common.DefineCreateFlags(cmd, &cliVals, false, false)
common.DefineCreateFlags(cmd, &cliVals, entities.CreateMode)
common.DefineNetFlags(cmd)

flags.SetNormalizeFunc(utils.AliasFlags)
Expand Down
83 changes: 83 additions & 0 deletions cmd/podman/containers/update.go
@@ -0,0 +1,83 @@
package containers

import (
"context"
"fmt"

"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/specgenutil"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/spf13/cobra"
)

var (
updateDescription = `Updates the cgroup configuration of a given container`

updateCommand = &cobra.Command{
Use: "update [options] CONTAINER",
Short: "update an existing container",
Long: updateDescription,
RunE: update,
Args: cobra.ExactArgs(1),
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman update --cpus=5 foobar_container`,
}

containerUpdateCommand = &cobra.Command{
Args: updateCommand.Args,
Use: updateCommand.Use,
Short: updateCommand.Short,
Long: updateCommand.Long,
RunE: updateCommand.RunE,
ValidArgsFunction: updateCommand.ValidArgsFunction,
Example: `podman container update --cpus=5 foobar_container`,
}
)
var (
updateOpts entities.ContainerCreateOptions
)

func updateFlags(cmd *cobra.Command) {
common.DefineCreateDefaults(&updateOpts)
common.DefineCreateFlags(cmd, &updateOpts, entities.UpdateMode)
}

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: updateCommand,
})
updateFlags(updateCommand)

registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerUpdateCommand,
Parent: containerCmd,
})
updateFlags(containerUpdateCommand)
}

func update(cmd *cobra.Command, args []string) error {
var err error
// use a specgen since this is the easiest way to hold resource info
s := &specgen.SpecGenerator{}
s.ResourceLimits = &specs.LinuxResources{}

// we need to pass the whole specgen since throttle devices are parsed later due to cross compat.
s.ResourceLimits, err = specgenutil.GetResources(s, &updateOpts)
if err != nil {
return err
}

opts := &entities.ContainerUpdateOptions{
NameOrID: args[0],
Specgen: s,
}
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
if err != nil {
return err
}
fmt.Println(rep)
return nil
}
2 changes: 1 addition & 1 deletion cmd/podman/pods/clone.go
Expand Up @@ -44,7 +44,7 @@ func cloneFlags(cmd *cobra.Command) {
_ = podCloneCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)

common.DefineCreateDefaults(&podClone.InfraOptions)
common.DefineCreateFlags(cmd, &podClone.InfraOptions, true, false)
common.DefineCreateFlags(cmd, &podClone.InfraOptions, entities.InfraMode)

podClone.InfraOptions.MemorySwappiness = -1 // this is not implemented for pods yet, need to set -1 default manually

Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/pods/create.go
Expand Up @@ -65,7 +65,7 @@ func init() {
flags := createCommand.Flags()
flags.SetInterspersed(false)
common.DefineCreateDefaults(&infraOptions)
common.DefineCreateFlags(createCommand, &infraOptions, true, false)
common.DefineCreateFlags(createCommand, &infraOptions, entities.InfraMode)
common.DefineNetFlags(createCommand)

flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/.gitignore
Expand Up @@ -6,3 +6,4 @@ podman-pod-clone.1.md
podman-pod-create.1.md
podman-pull.1.md
podman-run.1.md
podman-update.1.md
1 change: 1 addition & 0 deletions docs/source/markdown/links/podman-container-update.1
@@ -0,0 +1 @@
.so man1/podman-update.1
9 changes: 9 additions & 0 deletions docs/source/markdown/options/cpus.md
@@ -0,0 +1,9 @@
#### **--cpus**=*number*

Number of CPUs. The default is *0.0* which means no limit. This is shorthand
for **--cpu-period** and **--cpu-quota**, so you may only set either
**--cpus** or **--cpu-period** and **--cpu-quota**.

On some systems, changing the CPU limits may not be allowed for non-root
users. For more details, see
https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error
3 changes: 3 additions & 0 deletions docs/source/markdown/options/device-read-bps.md
@@ -0,0 +1,3 @@
#### **--device-read-bps**=*path*

Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb).
3 changes: 3 additions & 0 deletions docs/source/markdown/options/device-read-iops.md
@@ -0,0 +1,3 @@
#### **--device-read-iops**=*path:rate*

Limit read rate (in IO operations per second) from a device (e.g. **--device-read-iops=/dev/sda:1000**).
3 changes: 3 additions & 0 deletions docs/source/markdown/options/device-write-bps.md
@@ -0,0 +1,3 @@
#### **--device-write-bps**=*path:rate*

Limit write rate (in bytes per second) to a device (e.g. **--device-write-bps=/dev/sda:1mb**).
3 changes: 3 additions & 0 deletions docs/source/markdown/options/device-write-iops.md
@@ -0,0 +1,3 @@
#### **--device-write-iops**=*path*

Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)
9 changes: 9 additions & 0 deletions docs/source/markdown/options/memory-reservation.md
@@ -0,0 +1,9 @@
#### **--memory-reservation**=*limit*

Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
reservation. So you should always set the value below **--memory**, otherwise the
hard limit will take precedence. By default, memory reservation will be the same
as memory limit.
10 changes: 10 additions & 0 deletions docs/source/markdown/options/memory-swap.md
@@ -0,0 +1,10 @@
#### **--memory-swap**=*limit*

A limit value equal to memory plus swap. Must be used with the **-m**
(**--memory**) flag. The swap `LIMIT` should always be larger than **-m**
(**--memory**) value. By default, the swap `LIMIT` will be set to double
the value of --memory.

The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
`k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
9 changes: 9 additions & 0 deletions docs/source/markdown/options/memory.md
@@ -0,0 +1,9 @@
#### **--memory**, **-m**=*limit*

Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
not limited. The actual limit may be rounded up to a multiple of the operating
system's page size (the value would be very large, that's millions of trillions).
8 changes: 2 additions & 6 deletions docs/source/markdown/podman-container-clone.1.md.in
Expand Up @@ -50,13 +50,9 @@ If none are specified, the original container's CPU memory nodes are used.

@@option destroy

#### **--device-read-bps**=*path*
@@option device-read-bps

Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb).

#### **--device-write-bps**=*path*

Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)
@@option device-write-bps

#### **--force**, **-f**

Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-container.1.md
Expand Up @@ -46,6 +46,7 @@ The container command allows you to manage containers
| top | [podman-top(1)](podman-top.1.md) | Display the running processes of a container. |
| unmount | [podman-unmount(1)](podman-unmount.1.md) | Unmount a working container's root filesystem.(Alias unmount) |
| unpause | [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. |
| update | [podman-update(1)](podman-update.1.md) | Updates the cgroup configuration of a given container. |
| wait | [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. |

## SEE ALSO
Expand Down

0 comments on commit 5f757cb

Please sign in to comment.