diff options
-rw-r--r-- | .cirrus.yml | 6 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 10 | ||||
-rw-r--r-- | cmd/podman/common/create_opts.go | 1 | ||||
-rw-r--r-- | cmd/podman/common/specgen.go | 1 | ||||
-rw-r--r-- | cmd/podman/containers/stop.go | 3 | ||||
-rw-r--r-- | cmd/podman/generate/systemd.go | 2 | ||||
-rw-r--r-- | cmd/podman/utils/alias.go | 11 | ||||
-rw-r--r-- | contrib/cirrus/lib.sh | 23 | ||||
-rw-r--r-- | docs/source/markdown/podman-container-cleanup.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-create.1.md | 22 | ||||
-rw-r--r-- | docs/source/markdown/podman-generate-systemd.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 22 | ||||
-rw-r--r-- | docs/source/markdown/podman.1.md | 2 | ||||
-rw-r--r-- | libpod/container_config.go | 2 | ||||
-rw-r--r-- | libpod/container_inspect.go | 2 | ||||
-rw-r--r-- | libpod/define/container_inspect.go | 4 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 4 | ||||
-rw-r--r-- | libpod/options.go | 13 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 3 | ||||
-rw-r--r-- | pkg/specgen/specgen.go | 5 | ||||
-rw-r--r-- | test/e2e/generate_systemd_test.go | 2 | ||||
-rw-r--r-- | test/e2e/run_test.go | 3 | ||||
-rw-r--r-- | test/system/030-run.bats | 23 |
23 files changed, 139 insertions, 29 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index f044b98ab..e56ba9086 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -26,11 +26,11 @@ env: #### FEDORA_NAME: "fedora-34beta" PRIOR_FEDORA_NAME: "fedora-33" - UBUNTU_NAME: "ubuntu-2010" - PRIOR_UBUNTU_NAME: "ubuntu-2004" + UBUNTU_NAME: "ubuntu-2104" + PRIOR_UBUNTU_NAME: "ubuntu-2010" # Google-cloud VM Images - IMAGE_SUFFIX: "c5032481331085312" + IMAGE_SUFFIX: "c6731272010596352" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}" diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index d496ae308..c3d00d293 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -651,7 +651,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { createFlags.UintVar( &cf.StopTimeout, stopTimeoutFlagName, containerConfig.Engine.StopTimeout, - "Timeout (in seconds) to stop a container. Default is 10", + "Timeout (in seconds) that containers stopped by user command have to exit. If exceeded, the container will be forcibly stopped via SIGKILL.", ) _ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone) @@ -697,6 +697,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ) _ = cmd.RegisterFlagCompletionFunc(systemdFlagName, AutocompleteSystemdFlag) + timeoutFlagName := "timeout" + createFlags.UintVar( + &cf.Timeout, + timeoutFlagName, 0, + "Maximum length of time a container is allowed to run. The container will be killed automatically after the time expires.", + ) + _ = cmd.RegisterFlagCompletionFunc(timeoutFlagName, completion.AutocompleteNone) + tmpfsFlagName := "tmpfs" createFlags.StringArrayVar( &cf.TmpFS, diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 983b9e5ca..ca36d751e 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -108,6 +108,7 @@ type ContainerCLIOpts struct { SubGIDName string Sysctl []string Systemd string + Timeout uint TmpFS []string TTY bool Timezone string diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 310a07a00..f889a0169 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -641,6 +641,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string } s.Remove = c.Rm s.StopTimeout = &c.StopTimeout + s.Timeout = c.Timeout s.Timezone = c.Timezone s.Umask = c.Umask s.Secrets = c.Secrets diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go index bed45f374..62ce9b036 100644 --- a/cmd/podman/containers/stop.go +++ b/cmd/podman/containers/stop.go @@ -72,7 +72,8 @@ func stopFlags(cmd *cobra.Command) { _ = flags.MarkHidden("cidfile") _ = flags.MarkHidden("ignore") } - flags.SetNormalizeFunc(utils.AliasFlags) + + flags.SetNormalizeFunc(utils.TimeoutAliasFlags) } func init() { diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go index 72b2e6335..8a8f5016a 100644 --- a/cmd/podman/generate/systemd.go +++ b/cmd/podman/generate/systemd.go @@ -74,7 +74,7 @@ func init() { flags.StringVar(&format, formatFlagName, "", "Print the created units in specified format (json)") _ = systemdCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil)) - flags.SetNormalizeFunc(utils.AliasFlags) + flags.SetNormalizeFunc(utils.TimeoutAliasFlags) } func systemd(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/utils/alias.go b/cmd/podman/utils/alias.go index 8d089920b..306e610d9 100644 --- a/cmd/podman/utils/alias.go +++ b/cmd/podman/utils/alias.go @@ -17,8 +17,6 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName { name = "health-timeout" case "net": name = "network" - case "timeout": - name = "time" case "namespace": name = "ns" case "storage": @@ -34,3 +32,12 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName { } return pflag.NormalizedName(name) } + +// TimeoutAliasFlags is a function to handle backwards compatibility with old timeout flags +func TimeoutAliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "timeout": + name = "time" + } + return pflag.NormalizedName(name) +} diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 2cd28e34a..16eb6735a 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -10,27 +10,17 @@ set -a # handling of the (otherwise) default shell setup is non-uniform. Rather # than attempt to workaround differences, simply force-load/set required # items every time this library is utilized. -_waserrexit=0 -if [[ "$SHELLOPTS" =~ errexit ]]; then _waserrexit=1; fi -set +e # Assumed in F33 for setting global vars -if [[ -r "/etc/automation_environment" ]]; then - source /etc/automation_environment -else # prior to automation library v2.0, this was necessary - source /etc/profile - source /etc/environment -fi -if [[ -r "/etc/ci_environment" ]]; then source /etc/ci_environment; fi USER="$(whoami)" HOME="$(getent passwd $USER | cut -d : -f 6)" # Some platforms set and make this read-only [[ -n "$UID" ]] || \ UID=$(getent passwd $USER | cut -d : -f 3) -if ((_waserrexit)); then set -e; fi -# During VM Image build, the 'containers/automation' installation -# was performed. The final step of installation sets the library -# location $AUTOMATION_LIB_PATH in /etc/environment or in the -# default shell profile depending on distribution. +# Automation library installed at image-build time, +# defining $AUTOMATION_LIB_PATH in this file. +if [[ -r "/etc/automation_environment" ]]; then + source /etc/automation_environment +fi # shellcheck disable=SC2154 if [[ -n "$AUTOMATION_LIB_PATH" ]]; then # shellcheck source=/usr/share/automation/lib/common_lib.sh @@ -43,6 +33,9 @@ else ) > /dev/stderr fi +# Managed by setup_environment.sh; holds task-specific definitions. +if [[ -r "/etc/ci_environment" ]]; then source /etc/ci_environment; fi + OS_RELEASE_ID="$(source /etc/os-release; echo $ID)" # GCE image-name compatible string representation of distribution _major_ version OS_RELEASE_VER="$(source /etc/os-release; echo $VERSION_ID | tr -d '.')" diff --git a/docs/source/markdown/podman-container-cleanup.1.md b/docs/source/markdown/podman-container-cleanup.1.md index bd650c6af..9f9b90fc2 100644 --- a/docs/source/markdown/podman-container-cleanup.1.md +++ b/docs/source/markdown/podman-container-cleanup.1.md @@ -48,7 +48,7 @@ After cleanup, remove the image entirely. `podman container cleanup --latest` ## SEE ALSO -podman(1), podman-container(1) +**podman**(1), **podman-container**(1), **conmon**(8). ## HISTORY Jun 2018, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 229bb82f5..ff3f86ec9 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -951,6 +951,12 @@ The `container_manage_cgroup` boolean must be enabled for this to be allowed on `setsebool -P container_manage_cgroup true` +#### **\-\-timeout**=*seconds* + +Maximimum time a container is allowed to run before conmon sends it the kill +signal. By default containers will run until they exit or are stopped by +`podman stop`. + #### **\-\-tmpfs**=*fs* Create a tmpfs mount @@ -1412,6 +1418,20 @@ $ podman start --attach ctr b ``` +## CONMON + +When Podman starts a container it actually executes the conmon program, which +then executes the OCI Runtime. Conmon is the container monitor. It is a small +program whose job is to watch the primary process of the container, and if the +container dies, save the exit code. It also holds open the tty of the +container, so that it can be attached to later. This is what allows Podman to +run in detached mode (backgrounded), so Podman can exit but conmon continues to +run. Each container has their own instance of conmon. Conmon waits for the +container to exit, gathers and saves the exit code, and then launches a Podman +process to complete the container cleanup, by shutting down the network and +storage. For more information on conmon, please reference the conmon(8) man +page. + ## FILES **/etc/subuid** @@ -1421,7 +1441,7 @@ NOTE: Use the environment variable `TMPDIR` to change the temporary storage loca ## SEE ALSO **podman**(1), **podman-secret**(1), **podman-save**(1), **podman-ps**(1), **podman-attach**(1), **podman-pod-create**(1), **podman-port**(1), **podman-start*(1), **podman-kill**(1), **podman-stop**(1), -**podman-generate-systemd**(1) **podman-rm**(1), **subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1), **proc**(5)**. +**podman-generate-systemd**(1) **podman-rm**(1), **subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1), **proc**(5), **conmon**(8). ## HISTORY October 2017, converted from Docker documentation to Podman by Dan Walsh for Podman `<dwalsh@redhat.com>` diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md index 431163d56..1d427d35b 100644 --- a/docs/source/markdown/podman-generate-systemd.1.md +++ b/docs/source/markdown/podman-generate-systemd.1.md @@ -233,7 +233,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS bb310a0780ae docker.io/library/alpine:latest /bin/sh 3 minutes ago Created busy_moser ``` ## SEE ALSO -[podman(1)](podman.1.md), [podman-container(1)](podman-container.1.md), systemctl(1), systemd.unit(5), systemd.service(5) +[**podman**(1)](podman.1.md), [**podman-container**(1)](podman-container.1.md), **systemctl**(1), **systemd.unit**(5), **systemd.service**(5), **conmon**(8). ## HISTORY April 2020, Updated details and added usecase to use generated .service files as root and non-root, by Sujil Shah (sushah at redhat dot com) diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 2e6d97a05..a41938ff6 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1024,6 +1024,12 @@ The **container_manage_cgroup** boolean must be enabled for this to be allowed o setsebool -P container_manage_cgroup true ``` +#### **\-\-timeout**=*seconds* + +Maximimum time a container is allowed to run before conmon sends it the kill +signal. By default containers will run until they exit or are stopped by +`podman stop`. + #### **\-\-tmpfs**=*fs* Create a tmpfs mount. @@ -1763,6 +1769,20 @@ $ podman run --env ENV*****=b alpine printenv ENV***** b ``` +## CONMON + +When Podman starts a container it actually executes the conmon program, which +then executes the OCI Runtime. Conmon is the container monitor. It is a small +program whose job is to watch the primary process of the container, and if the +container dies, save the exit code. It also holds open the tty of the +container, so that it can be attached to later. This is what allows Podman to +run in detached mode (backgrounded), so Podman can exit but conmon continues to +run. Each container has their own instance of conmon. Conmon waits for the +container to exit, gathers and saves the exit code, and then launches a Podman +process to complete the container cleanup, by shutting down the network and +storage. For more information on conmon, please reference the conmon(8) man +page. + ## FILES **/etc/subuid** @@ -1773,7 +1793,7 @@ NOTE: Use the environment variable `TMPDIR` to change the temporary storage loca ## SEE ALSO **podman**(1), **podman-save**(1), **podman-ps**(1), **podman-attach**(1), **podman-pod-create**(1), **podman-port**(1), **podman-start**(1), **podman-kill**(1), **podman-stop**(1), -**podman-generate-systemd**(1) **podman-rm**(1), **subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1), **proc**(5)**. +**podman-generate-systemd**(1) **podman-rm**(1), **subgid**(5), **subuid**(5), **containers.conf**(5), **systemd.unit**(5), **setsebool**(8), **slirp4netns**(1), **fuse-overlayfs**(1), **proc**(5), **conmon**(8). ## HISTORY September 2018, updated by Kunal Kushwaha `<kushwaha_kunal_v7@lab.ntt.co.jp>` diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 87bcd8802..3b90a0922 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -343,7 +343,7 @@ The Network File System (NFS) and other distributed file systems (for example: L For more information, please refer to the [Podman Troubleshooting Page](https://github.com/containers/podman/blob/master/troubleshooting.md). ## SEE ALSO -`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `containers.conf(5)`, `oci-hooks(5)`, `containers-policy.json(5)`, `crun(8)`, `runc(8)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)` +**containers-mounts.conf**(5), **containers-registries.conf**(5), **containers-storage.conf**(5), **buildah**(1), **containers.conf**(5), **oci-hooks**(5), **containers-policy.json**(5), **crun**(8), **runc**(8), **subuid**(5), **subgid**(5), **slirp4netns**(1), **conmon**(8). ## HISTORY Dec 2016, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/libpod/container_config.go b/libpod/container_config.go index d0572fbc2..ede6b1aab 100644 --- a/libpod/container_config.go +++ b/libpod/container_config.go @@ -298,6 +298,8 @@ type ContainerMiscConfig struct { StopSignal uint `json:"stopSignal,omitempty"` // StopTimeout is the signal that will be used to stop the container StopTimeout uint `json:"stopTimeout,omitempty"` + // Timeout is maximimum time a container will run before getting the kill signal + Timeout uint `json:"timeout,omitempty"` // Time container was created CreatedTime time.Time `json:"createdTime"` // CgroupManager is the cgroup manager used to create this container. diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 61cc43314..5b2103c92 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -304,6 +304,8 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp ctrConfig.WorkingDir = spec.Process.Cwd } + ctrConfig.StopTimeout = c.config.StopTimeout + ctrConfig.Timeout = c.config.Timeout ctrConfig.OpenStdin = c.config.Stdin ctrConfig.Image = c.config.RootfsImageName ctrConfig.SystemdMode = c.config.Systemd diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index 1a38f5b0a..c236f35b0 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -64,6 +64,10 @@ type InspectContainerConfig struct { Umask string `json:"Umask,omitempty"` // Secrets are the secrets mounted in the container Secrets []*InspectSecret `json:"Secrets,omitempty"` + // Timeout is time before container is killed by conmon + Timeout uint `json:"Timeout"` + // StopTimeout is time before container is stoped when calling stop + StopTimeout uint `json:"StopTimeout"` } // InspectRestartPolicy holds information about the container's restart policy. diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index c1acec977..1b1d4ad59 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -1024,6 +1024,10 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co args = append(args, "-i") } + if ctr.config.Timeout > 0 { + args = append(args, fmt.Sprintf("--timeout=%d", ctr.config.Timeout)) + } + if !r.enableKeyring { args = append(args, "--no-new-keyring") } diff --git a/libpod/options.go b/libpod/options.go index 103a9a80a..39415a817 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -769,6 +769,19 @@ func WithStopTimeout(timeout uint) CtrCreateOption { } } +// WithTimeout sets the maximum time a container is allowed to run" +func WithTimeout(timeout uint) CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + + ctr.config.Timeout = timeout + + return nil + } +} + // WithIDMappings sets the idmappings for the container func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption { return func(ctr *Container) error { diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 2f623bf10..277435ef1 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -325,6 +325,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.StopTimeout != nil { options = append(options, libpod.WithStopTimeout(*s.StopTimeout)) } + if s.Timeout != 0 { + options = append(options, libpod.WithTimeout(s.Timeout)) + } if s.LogConfiguration != nil { if len(s.LogConfiguration.Path) > 0 { options = append(options, libpod.WithLogPath(s.LogConfiguration.Path)) diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index e3d4b1436..fdcb7a0e0 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -83,6 +83,11 @@ type ContainerBasicConfig struct { // instead. // Optional. StopTimeout *uint `json:"stop_timeout,omitempty"` + // Timeout is a maximum time in seconds the container will run before + // main process is sent SIGKILL. + // If 0 is used, signal will not be sent. Container can run indefinitely + // Optional. + Timeout uint `json:"timeout,omitempty"` // LogConfiguration describes the logging for a container including // driver, path, and options. // Optional diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index 3a1da5d8c..75d778f10 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -242,7 +242,7 @@ var _ = Describe("Podman generate systemd", func() { n.WaitWithDefaultTimeout() Expect(n.ExitCode()).To(Equal(0)) - session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "42", "--name", "--new", "foo"}) + session := podmanTest.Podman([]string{"generate", "systemd", "--time", "42", "--name", "--new", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 93505d742..74bdfce2c 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -582,6 +582,9 @@ USER bin`, BB) if _, err := os.Stat("/sys/fs/cgroup/io.stat"); os.IsNotExist(err) { Skip("Kernel does not have io.stat") } + if _, err := os.Stat("/sys/fs/cgroup/system.slice/io.bfq.weight"); os.IsNotExist(err) { + Skip("Kernel does not support BFQ IO scheduler") + } session := podmanTest.Podman([]string{"run", "--rm", "--blkio-weight=15", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/io.bfq.weight"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 6e4dd32df..2b83fa56e 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -669,4 +669,27 @@ json-file | f is "$output" ".*HOME=/.*" } +@test "podman run --timeout - basic test" { + cid=timeouttest + t0=$SECONDS + run_podman 255 run --name $cid --timeout 10 $IMAGE sleep 60 + t1=$SECONDS + # Confirm that container is stopped. Podman-remote unfortunately + # cannot tell the difference between "stopped" and "exited", and + # spits them out interchangeably, so we need to recognize either. + run_podman inspect --format '{{.State.Status}} {{.State.ExitCode}}' $cid + is "$output" "\\(stopped\|exited\\) \-1" \ + "Status and exit code of stopped container" + + # This operation should take + # exactly 10 seconds. Give it some leeway. + delta_t=$(( $t1 - $t0 )) + [ $delta_t -gt 8 ] ||\ + die "podman stop: ran too quickly! ($delta_t seconds; expected >= 10)" + [ $delta_t -le 14 ] ||\ + die "podman stop: took too long ($delta_t seconds; expected ~10)" + + run_podman rm $cid +} + # vim: filetype=sh |