Skip to content

Commit

Permalink
Merge branch 'main' of github.com:containers/podman into man
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed Aug 21, 2024
2 parents d5cd388 + 43fe3eb commit 1d5bdce
Show file tree
Hide file tree
Showing 22 changed files with 150 additions and 24 deletions.
3 changes: 1 addition & 2 deletions .packit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ jobs:
update_release: false
packages: [podman-fedora]
dist_git_branches:
- fedora-development
- fedora-latest
- fedora-all

- job: propose_downstream
trigger: release
Expand Down
5 changes: 5 additions & 0 deletions cmd/podman/containers/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ func run(cmd *cobra.Command, args []string) error {
s.ImageArch = cliVals.Arch
s.ImageVariant = cliVals.Variant
s.Passwd = &runOpts.Passwd

if runRmi {
s.RemoveImage = &runRmi
}

runOpts.Spec = s

if err := createPodIfNecessary(cmd, s, cliVals.Net); err != nil {
Expand Down
15 changes: 8 additions & 7 deletions docs/source/markdown/options/volume.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ content with a shared content label. Shared volume labels allow all containers
to read/write content. The **Z** option tells Podman to label the content with
a private unshared label Only the current <<container|pod>> can use a private
volume. Note: all containers within a `pod` share the same SELinux label. This
means all containers within said pod can read/write volumes create with the
`:Z`. Relabeling walks the file system under the volume and changes the label
on each file, if the volume has thousands of inodes, this process takes a
long time, delaying the start of the <<container|pod>>. If the volume
was previously relabeled with the `z` option, Podman is optimized to not relabel
a second time. If files are moved into the volume, then the labels can be
manually change with the `chcon -Rt container_file_t PATH` command.
means all containers within said pod can read/write volumes shared into the
container created with the `:Z` on any of one the containers. Relabeling walks
the file system under the volume and changes the label on each file, if the
volume has thousands of inodes, this process takes a long time, delaying the
start of the <<container|pod>>. If the volume was previously relabeled with the
`z` option, Podman is optimized to not relabel a second time. If files are
moved into the volume, then the labels can be manually change with the
`chcon -Rt container_file_t PATH` command.

Note: Do not relabel system files and directories. Relabeling system content
might cause other confined services on the machine to fail. For these types
Expand Down
11 changes: 11 additions & 0 deletions docs/source/markdown/podman-systemd.unit.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ Valid options for `[Container]` are listed below:
| AddDevice=/dev/foo | --device /dev/foo |
| Annotation="XYZ" | --annotation "XYZ" |
| AutoUpdate=registry | --label "io.containers.autoupdate=registry" |
| CgroupsMode=no-conmon | --cgroups=no-conmon |
| ContainerName=name | --name name |
| ContainersConfModule=/etc/nvd\.conf | --module=/etc/nvd\.conf |
| DNS=192.168.55.1 | --dns=192.168.55.1 |
Expand Down Expand Up @@ -370,6 +371,16 @@ Indicates whether the container will be auto-updated ([podman-auto-update(1)](po

* `local`: Tells Podman to compare the image a container is using to the image with its raw name in local storage. If an image is updated locally, Podman simply restarts the systemd unit executing the container.

### `CgroupsMode=`

The cgroups mode of the Podman container. Equivalent to the Podman `--cgroups` option.

By default, the cgroups mode of the container created by Quadlet is `split`,
which differs from the default (`enabled`) used by the Podman CLI.

If the container joins a pod (i.e. `Pod=` is specified), you may want to change this to
`no-conmon` or `enabled` so that pod level cgroup resource limits can take effect.

### `ContainerName=`

The (optional) name of the Podman container. If this is not specified, the default value
Expand Down
11 changes: 11 additions & 0 deletions libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,17 @@ func (c *Container) AutoRemove() bool {
return spec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue
}

// AutoRemoveImage indicates that the container will automatically remove the
// image it is using after it exits and is removed.
// Only allowed if AutoRemove is true.
func (c *Container) AutoRemoveImage() bool {
spec := c.config.Spec
if spec.Annotations == nil {
return false
}
return spec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue
}

// Timezone returns the timezone configured inside the container.
// Local means it has the same timezone as the host machine
func (c *Container) Timezone() string {
Expand Down
3 changes: 3 additions & 0 deletions libpod/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
if ctrSpec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue {
hostConfig.AutoRemove = true
}
if ctrSpec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue {
hostConfig.AutoRemoveImage = true
}
if ctrs, ok := ctrSpec.Annotations[define.VolumesFromAnnotation]; ok {
hostConfig.VolumesFrom = strings.Split(ctrs, ";")
}
Expand Down
12 changes: 12 additions & 0 deletions libpod/container_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ func (c *Container) validate() error {
}
}

// Autoremoving image requires autoremoving the associated container
if c.config.Spec.Annotations != nil {
if c.config.Spec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue {
if c.config.Spec.Annotations[define.InspectAnnotationAutoremove] != define.InspectResponseTrue {
return fmt.Errorf("autoremoving image requires autoremoving the container: %w", define.ErrInvalidArg)
}
if c.config.Rootfs != "" {
return fmt.Errorf("autoremoving image is not possible when a rootfs is in use: %w", define.ErrInvalidArg)
}
}
}

// Cannot set startup HC without a healthcheck
if c.config.HealthCheckConfig == nil && c.config.StartupHealthCheckConfig != nil {
return fmt.Errorf("cannot set a startup healthcheck when there is no regular healthcheck: %w", define.ErrInvalidArg)
Expand Down
6 changes: 6 additions & 0 deletions libpod/define/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ const (
// the two supported boolean values (InspectResponseTrue and
// InspectResponseFalse) it will be used in the output of Inspect().
InspectAnnotationAutoremove = "io.podman.annotations.autoremove"
// InspectAnnotationAutoremoveImage is used by Inspect to identify
// containers which will automatically remove the image used by the
// container. If an annotation with this key is found in the OCI spec and
// is one of the two supported boolean values (InspectResponseTrue and
// InspectResponseFalse) it will be used in the output of Inspect().
InspectAnnotationAutoremoveImage = "io.podman.annotations.autoremove-image"
// InspectAnnotationPrivileged is used by Inspect to identify containers
// which are privileged (IE, running with elevated privileges).
// It is expected to be a boolean, populated by one of
Expand Down
5 changes: 5 additions & 0 deletions libpod/define/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ type InspectContainerHostConfig struct {
// It is not handled directly within libpod and is stored in an
// annotation.
AutoRemove bool `json:"AutoRemove"`
// AutoRemoveImage is whether the container's image will be
// automatically removed on exiting.
// It is not handled directly within libpod and is stored in an
// annotation.
AutoRemoveImage bool `json:"AutoRemoveImage"`
// Annotations are provided to the runtime when the container is
// started.
Annotations map[string]string `json:"Annotations"`
Expand Down
2 changes: 1 addition & 1 deletion libpod/oci_conmon_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
args = append(args, "--no-pivot")
}

exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, ctr.runtime.syslog || logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), false)
exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, ctr.runtime.syslog || logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), ctr.AutoRemoveImage(), false)
if err != nil {
return 0, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/handlers/compat/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Automatically log to syslog if the server has log-level=debug set
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, true)
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, false, true)
if err != nil {
utils.InternalServerError(w, err)
return
Expand Down
39 changes: 30 additions & 9 deletions pkg/domain/infra/abi/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/containers/podman/v5/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/types"
"github.com/hashicorp/go-multierror"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -291,15 +292,35 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return err
}
}
err = c.Cleanup(ctx)
if err != nil {
// Issue #7384 and #11384: If the container is configured for
// auto-removal, it might already have been removed at this point.
// We still need to clean up since we do not know if the other cleanup process is successful
if c.AutoRemove() && (errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) {
return nil
if c.AutoRemove() {
_, imageName := c.Image()

if err := ic.Libpod.RemoveContainer(ctx, c, false, true, nil); err != nil {
// Issue #7384 and #11384: If the container is configured for
// auto-removal, it might already have been removed at this point.
// We still need to clean up since we do not know if the other cleanup process is successful
if !(errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) {
return err
}
}

if c.AutoRemoveImage() {
imageEngine := ImageEngine{Libpod: ic.Libpod}
_, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{Ignore: true})
if len(rmErrors) > 0 {
mErr := multierror.Append(nil, rmErrors...)
return fmt.Errorf("removing container %s image %s: %w", c.ID(), imageName, mErr)
}
}
} else {
if err = c.Cleanup(ctx); err != nil {
// The container could still have been removed, as we unlocked
// after we stopped it.
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
return nil
}
return err
}
return err
}
return nil
})
Expand Down Expand Up @@ -827,7 +848,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E
return nil, fmt.Errorf("retrieving Libpod configuration to build exec exit command: %w", err)
}
// TODO: Add some ability to toggle syslog
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true)
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, false, true)
if err != nil {
return nil, fmt.Errorf("constructing exit command for exec session: %w", err)
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/machine/apple/vfkit/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ func (vf *Helper) stateChange(newState rest.StateChange) error {
}
payload := bytes.NewReader(b)
serverResponse, err := vf.post(vf.Endpoint+state, payload)
_ = serverResponse.Body.Close()
if err == nil {
_ = serverResponse.Body.Close()
}
return err
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/specgen/generate/oci_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
}

if s.RemoveImage != nil && *s.RemoveImage {
configSpec.Annotations[define.InspectAnnotationAutoremoveImage] = define.InspectResponseTrue
}

if len(s.VolumesFrom) > 0 {
configSpec.Annotations[define.VolumesFromAnnotation] = strings.Join(s.VolumesFrom, ";")
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/specgen/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ type ContainerBasicConfig struct {
// and exits.
// Optional.
Remove *bool `json:"remove,omitempty"`
// RemoveImage indicates that the container should remove the image it
// was created from after it exits.
// Only allowed if Remove is set to true and Image, not Rootfs, is in
// use.
// Optional.
RemoveImage *bool `json:"removeImage,omitempty"`
// ContainerCreateCommand is the command that was used to create this
// container.
// This will be shown in the output of Inspect() on the container, and
Expand Down
6 changes: 5 additions & 1 deletion pkg/specgenutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func parseAndValidatePort(port string) (uint16, error) {
return uint16(num), nil
}

func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *config.Config, syslog, rm, exec bool) ([]string, error) {
func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *config.Config, syslog, rm, rmi, exec bool) ([]string, error) {
// We need a cleanup process for containers in the current model.
// But we can't assume that the caller is Podman - it could be another
// user of the API.
Expand Down Expand Up @@ -317,6 +317,10 @@ func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *conf
command = append(command, "--rm")
}

if rmi {
command = append(command, "--rmi")
}

// This has to be absolutely last, to ensure that the exec session ID
// will be added after it by Libpod.
if exec {
Expand Down
10 changes: 9 additions & 1 deletion pkg/systemd/quadlet/quadlet.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const (
KeyAuthFile = "AuthFile"
KeyAutoUpdate = "AutoUpdate"
KeyCertDir = "CertDir"
KeyCgroupsMode = "CgroupsMode"
KeyConfigMap = "ConfigMap"
KeyContainerName = "ContainerName"
KeyContainersConfModule = "ContainersConfModule"
Expand Down Expand Up @@ -191,6 +192,7 @@ var (
KeyAddDevice: true,
KeyAnnotation: true,
KeyAutoUpdate: true,
KeyCgroupsMode: true,
KeyContainerName: true,
KeyContainersConfModule: true,
KeyDNS: true,
Expand Down Expand Up @@ -581,7 +583,12 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[

// We delegate groups to the runtime
service.Add(ServiceGroup, "Delegate", "yes")
podman.add("--cgroups=split")

if cgroupsMode, ok := container.Lookup(ContainerGroup, KeyCgroupsMode); ok && len(cgroupsMode) > 0 {
podman.addf("--cgroups=%s", cgroupsMode)
} else {
podman.add("--cgroups=split")
}

timezone, ok := container.Lookup(ContainerGroup, KeyTimezone)
if ok && len(timezone) > 0 {
Expand Down Expand Up @@ -1656,6 +1663,7 @@ func ConvertPod(podUnit *parser.UnitFile, name string, unitsInfoMap map[string]*
return nil, err
}

execStartPre.addf("--infra-name=%s-infra", podName)
execStartPre.addf("--name=%s", podName)

handlePodmanArgs(podUnit, PodGroup, execStartPre)
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/quadlet/basic.pod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## assert-key-is Unit RequiresMountsFor "%t/containers"
## assert-key-is Service Type forking
## assert-key-is Service SyslogIdentifier "%N"
## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --pod-id-file=%t/%N.pod-id --exit-policy=stop --replace --name=systemd-basic"
## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --pod-id-file=%t/%N.pod-id --exit-policy=stop --replace --infra-name=systemd-basic-infra --name=systemd-basic"
## assert-key-is-regex Service ExecStart ".*/podman pod start --pod-id-file=%t/%N.pod-id"
## assert-key-is-regex Service ExecStop ".*/podman pod stop --pod-id-file=%t/%N.pod-id --ignore --time=10"
## assert-key-is-regex Service ExecStopPost ".*/podman pod rm --pod-id-file=%t/%N.pod-id --ignore --force"
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/quadlet/cgroups-mode.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## assert-podman-args --cgroups=no-conmon

[Container]
Image=localhost/imagename
CgroupsMode=no-conmon
1 change: 1 addition & 0 deletions test/e2e/quadlet/name.pod
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## assert-podman-pre-args "--name=test-pod"
## assert-podman-pre-args "--infra-name=test-pod-infra"

[Pod]
PodName=test-pod
1 change: 1 addition & 0 deletions test/e2e/quadlet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ BOGUS=foo
Entry("template@instance.container", "template@instance.container"),
Entry("Unit After Override", "unit-after-override.container"),
Entry("NetworkAlias", "network-alias.container"),
Entry("CgroupMode", "cgroups-mode.container"),

Entry("basic.volume", "basic.volume"),
Entry("device-copy.volume", "device-copy.volume"),
Expand Down
21 changes: 21 additions & 0 deletions test/system/030-run.bats
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,27 @@ echo $rand | 0 | $rand

run_podman 125 run --rmi --rm=false $NONLOCAL_IMAGE /bin/true
is "$output" "Error: the --rmi option does not work without --rm" "--rmi should refuse to remove images when --rm=false set by user"

# Try again with a detached container and verify it works
cname=c_$(safename)
run_podman run -d --name $cname --rmi $NONLOCAL_IMAGE /bin/true
# 10 chances for the image to disappear
for i in `seq 1 10`; do
sleep 0.5
run_podman '?' image exists $NONLOCAL_IMAGE
if [[ $status == 1 ]]; then
break
fi
done
# Final check will error if image still exists
run_podman 1 image exists $NONLOCAL_IMAGE

# Verify that the inspect annotation is set correctly
run_podman run -d --name $cname --rmi $NONLOCAL_IMAGE sleep 10
run_podman inspect --format '{{ .HostConfig.AutoRemoveImage }} {{ .HostConfig.AutoRemove }}' $cname
is "$output" "true true" "Inspect correctly shows image autoremove and normal autoremove"
run_podman stop -t0 $cname
run_podman 1 image exists $NONLOCAL_IMAGE
}

# 'run --conmon-pidfile --cid-file' makes sure we don't regress on these flags.
Expand Down

0 comments on commit 1d5bdce

Please sign in to comment.