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:

this command is also now supported in the libpod api via the /libpod/containers/<CID>/update endpoint where
the resource limits are passed inthe request body and follow the OCI resource spec format

–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 31, 2022
1 parent 8266dbe commit fd32f79
Show file tree
Hide file tree
Showing 49 changed files with 883 additions and 306 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 @@ -597,7 +581,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 @@ -677,7 +661,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 @@ -690,7 +674,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 @@ -725,7 +709,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 @@ -775,7 +759,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 @@ -791,7 +776,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 @@ -840,8 +826,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 @@ -27,3 +27,4 @@ podman-run.1.md
podman-search.1.md
podman-stop.1.md
podman-unpause.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
5 changes: 5 additions & 0 deletions docs/source/markdown/options/device-read-bps.md
@@ -0,0 +1,5 @@
#### **--device-read-bps**=*path:rate*

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

This option is not supported on cgroups V1 rootless systems.
5 changes: 5 additions & 0 deletions docs/source/markdown/options/device-read-iops.md
@@ -0,0 +1,5 @@
#### **--device-read-iops**=*path:rate*

Limit read rate (in IO operations per second) from a device (e.g. **--device-read-iops=/dev/sda:1000**).

This option is not supported on cgroups V1 rootless systems.
5 changes: 5 additions & 0 deletions docs/source/markdown/options/device-write-bps.md
@@ -0,0 +1,5 @@
#### **--device-write-bps**=*path:rate*

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

This option is not supported on cgroups V1 rootless systems.
5 changes: 5 additions & 0 deletions docs/source/markdown/options/device-write-iops.md
@@ -0,0 +1,5 @@
#### **--device-write-iops**=*path:rate*

Limit write rate (in IO operations per second) to a device (e.g. **--device-write-iops=/dev/sda:1000**).

This option is not supported on cgroups V1 rootless systems.
11 changes: 11 additions & 0 deletions docs/source/markdown/options/memory-reservation.md
@@ -0,0 +1,11 @@
#### **--memory-reservation**=*number[unit]*

Memory soft limit. A _unit_ can be **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.

This option is not supported on cgroups V1 rootless systems.
13 changes: 13 additions & 0 deletions docs/source/markdown/options/memory-swap.md
@@ -0,0 +1,13 @@
#### **--memory-swap**=*number[unit]*

A limit value equal to memory plus swap.
A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).

Must be used with the **-m** (**--memory**) flag.
The argument value should always be larger than that of
**-m** (**--memory**) By default, it is set to double
the value of **--memory**.

Set _number_ to **-1** to enable unlimited swap.

This option is not supported on cgroups V1 rootless systems.
11 changes: 11 additions & 0 deletions docs/source/markdown/options/memory.md
@@ -0,0 +1,11 @@
#### **--memory**, **-m**=*number[unit]*

Memory limit. A _unit_ can be **b** (bytes), **k** (kibibytes), **m** (mebibytes), or **g** (gibibytes).

Allows the memory available to a container to be constrained. 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).

This option is not supported on cgroups V1 rootless systems.
26 changes: 3 additions & 23 deletions docs/source/markdown/podman-container-clone.1.md.in
Expand Up @@ -52,36 +52,18 @@ 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).

This option is not supported on cgroups V1 rootless systems.

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

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

This option is not supported on cgroups V1 rootless systems.
@@option device-write-bps

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

Force removal of the original container that we are cloning. Can only be used in conjunction with **--destroy**.

#### **--memory**, **-m**=*limit*

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

Allows the memory available to a container to be constrained. 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).
@@option memory

If no memory limits are specified, the original container's will be used.

This option is not supported on cgroups V1 rootless systems.

#### **--memory-reservation**=*limit*

Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
Expand All @@ -92,8 +74,6 @@ reservation. So you should always set the value below **--memory**, otherwise th
hard limit will take precedence. By default, memory reservation will be the same
as memory limit from the container being cloned.

This option is not supported on cgroups V1 rootless systems.

#### **--memory-swap**=*limit*

A limit value equal to memory plus swap. Must be used with the **-m**
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 fd32f79

Please sign in to comment.