summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_PROCESS.md2
-rw-r--r--cmd/podman-mac-helper/main.go4
-rw-r--r--cmd/podman/containers/cleanup.go2
-rw-r--r--cmd/podman/containers/port.go2
-rw-r--r--cmd/podman/machine/init.go19
-rw-r--r--cmd/podman/machine/list.go2
-rw-r--r--cmd/podman/registry/config.go4
-rw-r--r--cmd/podman/system/connection/add.go2
-rw-r--r--cmd/podman/validate/args.go4
-rw-r--r--cmd/winpath/main.go2
-rw-r--r--commands-demo.md2
-rw-r--r--contrib/cirrus/lib.sh6
-rwxr-xr-xcontrib/cirrus/logformatter53
-rwxr-xr-xcontrib/cirrus/runner.sh5
-rw-r--r--contrib/podmanimage/README.md4
-rw-r--r--docs/source/Tutorials.rst6
-rw-r--r--docs/source/markdown/podman-container-cleanup.1.md8
-rw-r--r--docs/source/markdown/podman-container.1.md2
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-port.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md4
-rw-r--r--docs/tutorials/README.md6
-rw-r--r--docs/tutorials/basic_networking.md15
-rw-r--r--docs/tutorials/podman_tutorial.md2
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/boltdb_state.go248
-rw-r--r--libpod/boltdb_state_internal.go22
-rw-r--r--libpod/container.go4
-rw-r--r--libpod/container_api.go97
-rw-r--r--libpod/container_internal.go64
-rw-r--r--libpod/container_internal_linux.go6
-rw-r--r--libpod/define/errors.go4
-rw-r--r--libpod/events.go3
-rw-r--r--libpod/healthcheck.go2
-rw-r--r--libpod/networking_linux.go4
-rw-r--r--libpod/oci_conmon_attach_linux.go2
-rw-r--r--libpod/oci_conmon_linux.go28
-rw-r--r--libpod/options.go2
-rw-r--r--libpod/runtime.go8
-rw-r--r--libpod/runtime_ctr.go10
-rw-r--r--libpod/state.go9
-rw-r--r--pkg/api/handlers/compat/containers_stats.go2
-rw-r--r--pkg/api/handlers/libpod/containers_stats.go2
-rw-r--r--pkg/api/handlers/utils/containers.go1
-rw-r--r--pkg/api/server/listener_api.go2
-rw-r--r--pkg/bindings/connection.go2
-rw-r--r--pkg/domain/infra/abi/containers.go36
-rw-r--r--pkg/domain/infra/abi/pods.go4
-rw-r--r--pkg/domain/infra/abi/system.go6
-rw-r--r--pkg/domain/infra/runtime_libpod.go4
-rw-r--r--pkg/domain/infra/tunnel/helpers.go4
-rw-r--r--pkg/machine/e2e/list_test.go23
-rw-r--r--pkg/machine/ignition.go4
-rw-r--r--pkg/machine/qemu/machine.go6
-rw-r--r--pkg/namespaces/namespaces.go2
-rw-r--r--pkg/rootless/rootless_linux.go4
-rw-r--r--pkg/systemd/generate/containers.go2
-rw-r--r--rootless.md4
-rw-r--r--test/e2e/checkpoint_test.go41
-rw-r--r--test/e2e/common_test.go2
-rw-r--r--test/e2e/create_staticip_test.go2
-rw-r--r--test/e2e/create_staticmac_test.go2
-rw-r--r--test/e2e/image_scp_test.go23
-rw-r--r--test/e2e/run_staticip_test.go2
-rw-r--r--test/e2e/system_connection_test.go24
-rw-r--r--test/framework/framework.go2
-rw-r--r--test/system/030-run.bats12
-rw-r--r--test/system/500-networking.bats6
-rw-r--r--troubleshooting.md4
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertion_compare.go24
-rw-r--r--vendor/modules.txt2
72 files changed, 645 insertions, 288 deletions
diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md
index 3f63e5466..66cc74693 100644
--- a/RELEASE_PROCESS.md
+++ b/RELEASE_PROCESS.md
@@ -162,7 +162,7 @@ spelled with complete minutiae.
release branch (`git checkout upstream/vX.Y`).
1. Create a new local working-branch to develop the release PR,
`git checkout -b bump_vX.Y.Z`.
- 1. Lookup the *COMMIT ID* of the last release,
+ 1. Look up the *COMMIT ID* of the last release,
`git log -1 $(git tag | sort -V | tail -1)`.
1. Edit `version/version.go` and bump the `Version` value to the new
release version. If there were API changes, also bump `APIVersion` value.
diff --git a/cmd/podman-mac-helper/main.go b/cmd/podman-mac-helper/main.go
index 8d995519f..735d9898f 100644
--- a/cmd/podman-mac-helper/main.go
+++ b/cmd/podman-mac-helper/main.go
@@ -73,7 +73,7 @@ func getUserInfo(name string) (string, string, string, error) {
entry := readCapped(output)
elements := strings.Split(entry, ":")
if len(elements) < 9 || elements[0] != name {
- return "", "", "", errors.New("Could not lookup user")
+ return "", "", "", errors.New("Could not look up user")
}
return elements[0], elements[2], elements[8], nil
@@ -90,7 +90,7 @@ func getUser() (string, string, string, error) {
_, uid, home, err := getUserInfo(name)
if err != nil {
- return "", "", "", fmt.Errorf("could not lookup user: %s", name)
+ return "", "", "", fmt.Errorf("could not look up user: %s", name)
}
id, err := strconv.Atoi(uid)
if err != nil {
diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go
index a63e413fe..18cec097c 100644
--- a/cmd/podman/containers/cleanup.go
+++ b/cmd/podman/containers/cleanup.go
@@ -23,7 +23,7 @@ var (
cleanupCommand = &cobra.Command{
Annotations: map[string]string{registry.EngineMode: registry.ABIMode},
Use: "cleanup [options] CONTAINER [CONTAINER...]",
- Short: "Cleanup network and mountpoints of one or more containers",
+ Short: "Clean up network and mountpoints of one or more containers",
Long: cleanupDescription,
RunE: cleanup,
Args: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index f10bdd5b4..fdb2f6c46 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -15,7 +15,7 @@ import (
)
var (
- portDescription = `List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
+ portDescription = `List port mappings for the CONTAINER, or look up the public-facing port that is NAT-ed to the PRIVATE_PORT
`
portCommand = &cobra.Command{
Use: "port [options] CONTAINER [PORT]",
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index 612c36057..9d464ad37 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -109,7 +109,7 @@ func init() {
flags.BoolVar(&initOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")
}
-func initMachine(_ *cobra.Command, args []string) error {
+func initMachine(cmd *cobra.Command, args []string) error {
var (
err error
vm machine.VM
@@ -147,17 +147,12 @@ func initMachine(_ *cobra.Command, args []string) error {
fmt.Println("Machine init complete")
if now {
- err = vm.Start(initOpts.Name, machine.StartOptions{})
- if err == nil {
- fmt.Printf("Machine %q started successfully\n", initOpts.Name)
- newMachineEvent(events.Start, events.Event{Name: initOpts.Name})
- }
- } else {
- extra := ""
- if initOpts.Name != defaultMachineName {
- extra = " " + initOpts.Name
- }
- fmt.Printf("To start your machine run:\n\n\tpodman machine start%s\n\n", extra)
+ return start(cmd, args)
+ }
+ extra := ""
+ if initOpts.Name != defaultMachineName {
+ extra = " " + initOpts.Name
}
+ fmt.Printf("To start your machine run:\n\n\tpodman machine start%s\n\n", extra)
return err
}
diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go
index bb14d4a67..1ffb8690c 100644
--- a/cmd/podman/machine/list.go
+++ b/cmd/podman/machine/list.go
@@ -138,7 +138,7 @@ func outputTemplate(cmd *cobra.Command, responses []*ListReporter) error {
switch {
case cmd.Flags().Changed("format"):
row = cmd.Flag("format").Value.String()
- listFlag.noHeading = !report.HasTable(row)
+ printHeader = report.HasTable(row)
row = report.NormalizeFormat(row)
default:
row = cmd.Flag("format").Value.String()
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index b5c9b359c..e06de034d 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -92,7 +92,7 @@ func setXdgDirs() error {
return nil
}
- // Setup XDG_RUNTIME_DIR
+ // Set up XDG_RUNTIME_DIR
if _, found := os.LookupEnv("XDG_RUNTIME_DIR"); !found {
dir, err := util.GetRuntimeDir()
if err != nil {
@@ -110,7 +110,7 @@ func setXdgDirs() error {
}
}
- // Setup XDG_CONFIG_HOME
+ // Set up XDG_CONFIG_HOME
if _, found := os.LookupEnv("XDG_CONFIG_HOME"); !found {
cfgHomeDir, err := util.GetRootlessConfigHomeDir()
if err != nil {
diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go
index 387de3c58..d77a39bcc 100644
--- a/cmd/podman/system/connection/add.go
+++ b/cmd/podman/system/connection/add.go
@@ -188,7 +188,7 @@ func GetUserInfo(uri *url.URL) (*url.Userinfo, error) {
if u, found := os.LookupEnv("_CONTAINERS_ROOTLESS_UID"); found {
usr, err = user.LookupId(u)
if err != nil {
- return nil, errors.Wrapf(err, "failed to lookup rootless user")
+ return nil, errors.Wrapf(err, "failed to look up rootless user")
}
} else {
usr, err = user.Current()
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index 4c40581c6..ae405e0e5 100644
--- a/cmd/podman/validate/args.go
+++ b/cmd/podman/validate/args.go
@@ -73,9 +73,9 @@ func CheckAllLatestAndIDFile(c *cobra.Command, args []string, ignoreArgLen bool,
specifiedLatest, _ = c.Flags().GetBool("latest")
if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
if idFileFlag == "" {
- return errors.New("unable to lookup values for 'latest' or 'all'")
+ return errors.New("unable to look up values for 'latest' or 'all'")
} else if c.Flags().Lookup(idFileFlag) == nil {
- return errors.Errorf("unable to lookup values for 'latest', 'all', or '%s'", idFileFlag)
+ return errors.Errorf("unable to look up values for 'latest', 'all', or '%s'", idFileFlag)
}
}
}
diff --git a/cmd/winpath/main.go b/cmd/winpath/main.go
index b7aa7330d..bb57e39de 100644
--- a/cmd/winpath/main.go
+++ b/cmd/winpath/main.go
@@ -131,7 +131,7 @@ func removePathFromRegistry(path string) error {
k, err := registry.OpenKey(registry.CURRENT_USER, Environment, registry.READ|registry.WRITE)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
- // Nothing to cleanup, the Environment registry key does not exist.
+ // Nothing to clean up, the Environment registry key does not exist.
return nil
}
return err
diff --git a/commands-demo.md b/commands-demo.md
index ececf0a22..50e2873b2 100644
--- a/commands-demo.md
+++ b/commands-demo.md
@@ -11,7 +11,7 @@
| [podman-commit(1)](https://podman.readthedocs.io/en/latest/markdown/podman-commit.1.html) | Create new image based on the changed container |
| [podman-container(1)](https://podman.readthedocs.io/en/latest/managecontainers.html) | Manage Containers |
| [podman-container-checkpoint(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-checkpoint.1.html) | Checkpoints one or more running containers |
-| [podman-container-cleanup(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-cleanup.1.html) | Cleanup the container's network and mountpoints |
+| [podman-container-cleanup(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-cleanup.1.html) | Clean up the container's network and mountpoints |
| [podman-container-exists(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-exists.1.html) | Check if an container exists in local storage |
| [podman-container-prune(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-prune.1.html) | Remove all stopped containers from local storage |
| [podman-container-restore(1)](https://podman.readthedocs.io/en/latest/markdown/podman-container-restore.1.html) | Restores one or more containers from a checkpoint |
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index 724f7c3d5..2624af385 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -173,7 +173,7 @@ setup_rootless() {
ssh-keygen -t ed25519 -P "" -f "/home/$ROOTLESS_USER/.ssh/id_ed25519"
ssh-keygen -t rsa -P "" -f "/home/$ROOTLESS_USER/.ssh/id_rsa"
- msg "Setup authorized_keys"
+ msg "Set up authorized_keys"
cat $HOME/.ssh/*.pub /home/$ROOTLESS_USER/.ssh/*.pub >> $HOME/.ssh/authorized_keys
cat $HOME/.ssh/*.pub /home/$ROOTLESS_USER/.ssh/*.pub >> /home/$ROOTLESS_USER/.ssh/authorized_keys
@@ -186,9 +186,9 @@ setup_rootless() {
# never be any non-localhost connections made from tests (using strict-mode).
# If there are, it's either a security problem or a broken test, both of which
# we want to lead to test failures.
- msg " setup known_hosts for $USER"
+ msg " set up known_hosts for $USER"
ssh-keyscan localhost > /root/.ssh/known_hosts
- msg " setup known_hosts for $ROOTLESS_USER"
+ msg " set up known_hosts for $ROOTLESS_USER"
# Maintain access-permission consistency with all other .ssh files.
install -Z -m 700 -o $ROOTLESS_USER -g $ROOTLESS_USER \
/root/.ssh/known_hosts /home/$ROOTLESS_USER/.ssh/known_hosts
diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter
index e45f03df9..59969c3e7 100755
--- a/contrib/cirrus/logformatter
+++ b/contrib/cirrus/logformatter
@@ -190,6 +190,22 @@ END_HTML
print { $out_fh } "<h2>Synopsis</h2>\n<hr/>\n",
job_synopsis($test_name), "<hr/>\n";
+ # FOR DEBUGGING: dump environment, but in HTML comments to not clutter
+ # This is safe. There is a TOKEN envariable, but it's not sensitive.
+ # There are no sensitive/secret values in our execution environment,
+ # but we're careful anyway. $SECRET_ENV_RE is set in lib.sh
+ my $filter_re = $ENV{SECRET_ENV_RE} || 'ACCOUNT|GC[EP]|PASSW|SECRET|TOKEN';
+ $filter_re .= '|BASH_FUNC'; # These are long and un-useful
+
+ print { $out_fh } "<!-- Environment: -->\n";
+ for my $e (sort keys %ENV) {
+ next if $e =~ /$filter_re/;
+
+ my $val = escapeHTML($ENV{$e});
+ $val =~ s/--/-&#x002D;/g; # double dash not valid in comments
+ printf { $out_fh } "<!-- %-20s %s -->\n", $e, $val;
+ }
+
# State variables
my $previous_timestamp = ''; # timestamp of previous line
my $cirrus_task; # Cirrus task number, used for linking
@@ -538,27 +554,24 @@ END_HTML
# If Cirrus magic envariables are available, write a link to results.
# FIXME: it'd be so nice to make this a clickable live link.
#
- # STATIC_MAGIC_BLOB is the name of a google-storage bucket. It is
- # unlikely to change often, but if it does you will suddenly start
- # seeing errors when trying to view formatted logs:
- #
- # AccessDeniedAccess denied.Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object.
- #
- # This happened in July 2020 when github.com/containers/libpod was
- # renamed to podman. If something like that ever happens again, you
- # will need to get the new magic blob value from:
- #
- # https://console.cloud.google.com/storage/browser?project=libpod-218412
+ # As of June 2022 we use the Cirrus API[1] as the source of our logs,
+ # instead of linking directly to googleapis.com. This will allow us
+ # to abstract cloud-specific details, so we can one day use Amazon cloud.
+ # See #14569 for more info.
#
- # You will also probably need to set the bucket Public by clicking on
- # the bucket name, then the Permissions tab. This is safe, since this
- # project is fully open-source.
- if ($have_formatted_log && $ENV{CIRRUS_TASK_ID}) {
- my $URL_BASE = "https://storage.googleapis.com";
- my $STATIC_MAGIC_BLOB = "cirrus-ci-6707778565701632-fcae48";
- my $ARTIFACT_NAME = "html";
-
- my $URL = "${URL_BASE}/${STATIC_MAGIC_BLOB}/artifacts/$ENV{CIRRUS_REPO_FULL_NAME}/$ENV{CIRRUS_TASK_ID}/${ARTIFACT_NAME}/${outfile}";
+ # [1] https://cirrus-ci.org/guide/writing-tasks/#latest-build-artifacts
+ if ($have_formatted_log && $ENV{CIRRUS_BUILD_ID} && $ENV{CIRRUS_TASK_NAME}) {
+ my $URL_BASE = "https://api.cirrus-ci.com";
+ my $build_id = $ENV{CIRRUS_BUILD_ID};
+ my $task_name = $ENV{CIRRUS_TASK_NAME};
+
+ # Escape spaces in task names ("int fedora 35 podman root etc")
+ $task_name =~ s/\s/%20/g;
+
+ # URL is long and cumbersome and duplicaty. The task name cannot be
+ # reduced; the file name could, but I choose to leave it because I
+ # sometimes download HTML logs and oh how I hate "log.html" filenames.
+ my $URL = "${URL_BASE}/v1/artifact/build/$build_id/$task_name/html/${outfile}";
print "\n\nAnnotated results:\n $URL\n";
}
diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh
index b9f43f395..d49286ad3 100755
--- a/contrib/cirrus/runner.sh
+++ b/contrib/cirrus/runner.sh
@@ -142,7 +142,10 @@ exec_container() {
# Line-separated arguments which include shell-escaped special characters
declare -a envargs
while read -r var_val; do
- envargs+=("-e $var_val")
+ # Pass "-e VAR" on the command line, not "-e VAR=value". Podman can
+ # do a much better job of transmitting the value than we can,
+ # especially when value includes spaces.
+ envargs+=("-e" "$(awk -F= '{print $1}' <<<$var_val)")
done <<<"$(passthrough_envars)"
# VM Images and Container images are built using (nearly) identical operations.
diff --git a/contrib/podmanimage/README.md b/contrib/podmanimage/README.md
index b4ef81d84..0f4f715ad 100644
--- a/contrib/podmanimage/README.md
+++ b/contrib/podmanimage/README.md
@@ -32,7 +32,9 @@ The container images are:
* `quay.io/podman/upstream:latest` - This image is built daily using the latest
code found in this GitHub repository. Due to the image changing frequently,
it's not guaranteed to be stable or even executable. The image is built with
- [the upstream Containerfile](upstream/Containerfile).
+ [the upstream Containerfile](upstream/Containerfile). Note the actual compilation
+ of upstream podman [occurs continuously in
+ COPR](https://copr.fedorainfracloud.org/coprs/rhcontainerbot/podman-next/).
## Sample Usage
diff --git a/docs/source/Tutorials.rst b/docs/source/Tutorials.rst
index c2cbcb8a9..024e6847c 100644
--- a/docs/source/Tutorials.rst
+++ b/docs/source/Tutorials.rst
@@ -4,11 +4,11 @@ Tutorials
=========
Here are a number of useful tutorials to get you up and running with Podman. If you are familiar with the Docker `Container Engine`_ the command in Podman_ should be quite familiar. If you are brand new to containers, take a look at our `Introduction`.
-* `Basic Setup and Use of Podman <https://github.com/containers/podman/blob/main/docs/tutorials/podman_tutorial.md>`_: Learn how to setup Podman and perform some basic commands with the utility.
-* `Basic Setup and Use of Podman in a Rootless environment <https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md>`_: The steps required to setup rootless Podman are enumerated.
+* `Basic Setup and Use of Podman <https://github.com/containers/podman/blob/main/docs/tutorials/podman_tutorial.md>`_: Learn how to set up Podman and perform some basic commands with the utility.
+* `Basic Setup and Use of Podman in a Rootless environment <https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md>`_: The steps required to set up rootless Podman are enumerated.
* `Podman for Windows <https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md>`_: A guide to installing and using Podman on Windows.
* `Podman Remote Clients on Mac/Windows <https://github.com/containers/podman/blob/main/docs/tutorials/mac_win_client.md>`_: Advanced setup for connecting to a remote Linux system using the Podman remote client on Mac and Windows.
-* `How to sign and distribute container images using Podman <https://github.com/containers/podman/blob/main/docs/tutorials/image_signing.md>`_: Learn how to setup and use image signing with Podman.
+* `How to sign and distribute container images using Podman <https://github.com/containers/podman/blob/main/docs/tutorials/image_signing.md>`_: Learn how to set up and use image signing with Podman.
* `Podman remote-client tutorial <https://github.com/containers/podman/blob/main/docs/tutorials/remote_client.md>`_: A brief how-to on using the Podman remote-client.
* `How to use libpod for custom/derivative projects <https://github.com/containers/podman/blob/main/docs/tutorials/podman-derivative-api.md>`_: How the libpod API can be used within your own project.
* `How to use Podman's Go RESTful bindings <https://github.com/containers/podman/tree/main/pkg/bindings>`_: An introduction to using our RESTful Golang bindings in an external application.
diff --git a/docs/source/markdown/podman-container-cleanup.1.md b/docs/source/markdown/podman-container-cleanup.1.md
index 0f182eded..0ad09efd3 100644
--- a/docs/source/markdown/podman-container-cleanup.1.md
+++ b/docs/source/markdown/podman-container-cleanup.1.md
@@ -1,7 +1,7 @@
% podman-container-cleanup(1)
## NAME
-podman\-container\-cleanup - Cleanup the container's network and mountpoints
+podman\-container\-cleanup - Clean up the container's network and mountpoints
## SYNOPSIS
**podman container cleanup** [*options*] *container* [*container* ...]
@@ -13,7 +13,7 @@ Sometimes container mount points and network stacks can remain if the podman com
## OPTIONS
#### **--all**, **-a**
-Cleanup all *containers*.\
+Clean up all *containers*.\
The default is **false**.\
*IMPORTANT: This OPTION does not need a container name or ID as input argument.*
@@ -40,12 +40,12 @@ After cleanup, remove the image entirely.\
The default is **false**.
## EXAMPLES
-Cleanup the container "mywebserver".
+Clean up the container "mywebserver".
```
$ podman container cleanup mywebserver
```
-Cleanup the containers with the names "mywebserver", "myflaskserver", "860a4b23".
+Clean up the containers with the names "mywebserver", "myflaskserver", "860a4b23".
```
$ podman container cleanup mywebserver myflaskserver 860a4b23
```
diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md
index 36623c718..a66e2789d 100644
--- a/docs/source/markdown/podman-container.1.md
+++ b/docs/source/markdown/podman-container.1.md
@@ -15,7 +15,7 @@ The container command allows you to manage containers
| --------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
| attach | [podman-attach(1)](podman-attach.1.md) | Attach to a running container. |
| checkpoint | [podman-container-checkpoint(1)](podman-container-checkpoint.1.md) | Checkpoints one or more running containers. |
-| cleanup | [podman-container-cleanup(1)](podman-container-cleanup.1.md) | Cleanup the container's network and mountpoints. |
+| cleanup | [podman-container-cleanup(1)](podman-container-cleanup.1.md) | Clean up the container's network and mountpoints. |
| clone | [podman-container-clone(1)](podman-container-clone.1.md) | Creates a copy of an existing container. |
| commit | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. |
| cp | [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. |
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 624b0b384..40fca0f3a 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -654,7 +654,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
· bind-propagation: shared, slave, private, unbindable, rshared, rslave, runbindable, or rprivate(default). See also mount(2).
- . bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive.
+ . bind-nonrecursive: do not set up a recursive bind mount. By default it is recursive.
. relabel: shared, private.
diff --git a/docs/source/markdown/podman-port.1.md b/docs/source/markdown/podman-port.1.md
index a72fc12bf..ebfeeccd7 100644
--- a/docs/source/markdown/podman-port.1.md
+++ b/docs/source/markdown/podman-port.1.md
@@ -9,7 +9,7 @@ podman\-port - List port mappings for a container
**podman container port** [*options*] *container* [*private-port*[/*proto*]]
## DESCRIPTION
-List port mappings for the *container* or lookup the public-facing port that is NAT-ed to the *private-port*.
+List port mappings for the *container* or look up the public-facing port that is NAT-ed to the *private-port*.
## OPTIONS
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 3b886e466..488bf6777 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -679,7 +679,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
· bind-propagation: shared, slave, private, unbindable, rshared, rslave, runbindable, or rprivate(default). See also mount(2).
- . bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive.
+ . bind-nonrecursive: do not set up a recursive bind mount. By default it is recursive.
. relabel: shared, private.
@@ -1883,7 +1883,7 @@ $ podman run --uidmap 0:30000:7000 --gidmap 0:30000:7000 fedora echo hello
Podman allows for the configuration of storage by changing the values
in the _/etc/container/storage.conf_ or by using global options. This
-shows how to setup and use fuse-overlayfs for a one time run of busybox
+shows how to set up and use fuse-overlayfs for a one time run of busybox
using global options.
```
diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md
index 2a3c85c55..c7c1a3616 100644
--- a/docs/tutorials/README.md
+++ b/docs/tutorials/README.md
@@ -6,11 +6,11 @@
**[Introduction Tutorial](podman_tutorial.md)**
-Learn how to setup Podman and perform some basic commands with the utility.
+Learn how to set up Podman and perform some basic commands with the utility.
**[Basic Setup and Use of Podman in a Rootless environment](rootless_tutorial.md)**
-The steps required to setup rootless Podman are enumerated.
+The steps required to set up rootless Podman are enumerated.
**[Setup Mac/Windows](mac_win_client.md)**
@@ -26,7 +26,7 @@ How the libpod API can be used within your own project.
**[Image Signing](image_signing.md)**
-Learn how to setup and use image signing with Podman.
+Learn how to set up and use image signing with Podman.
**[Basic Networking](basic_networking.md)**
diff --git a/docs/tutorials/basic_networking.md b/docs/tutorials/basic_networking.md
index b6f53175b..0a6034e7a 100644
--- a/docs/tutorials/basic_networking.md
+++ b/docs/tutorials/basic_networking.md
@@ -13,13 +13,14 @@ Each setup is supported with an example.
## Differences between rootful and rootless container networking
-One of the guiding factors on networking for containers with Podman is going to be
-whether or not the container is run by a root user or not. This is because unprivileged
-users cannot create networking interfaces on the host. Therefore, with rootful
-containers, the default networking mode is to use netavark.
-For rootless, the default network
-mode is slirp4netns. Because of the limited privileges, slirp4netns lacks some of
-the features of networking; for example, slirp4netns cannot give containers a
+One of the guiding factors on networking for containers with Podman is going to
+be whether or not the container is run by a root user or not. This is because
+unprivileged users cannot create networking interfaces on the host. Therefore,
+for rootless containers, the default network mode is slirp4netns. Because of the
+limited privileges, slirp4netns lacks some of the features of networking
+compared to rootful Podman's networking; for example, slirp4netns cannot give
+containers a routable IP address. The default networking mode for rootful
+containers on the other side is netavark, which allows a container to have a
routable IP address.
## Firewalls
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index 83f1e5e1e..a371189e9 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -142,7 +142,7 @@ podman rm --latest
You can verify the deletion of the container by running *podman ps -a*.
## Integration Tests
-For more information on how to setup and run the integration tests in your environment, checkout the Integration Tests [README.md](../../test/README.md)
+For more information on how to set up and run the integration tests in your environment, checkout the Integration Tests [README.md](../../test/README.md)
## More information
diff --git a/go.mod b/go.mod
index 6141fe007..2f196d9b9 100644
--- a/go.mod
+++ b/go.mod
@@ -57,7 +57,7 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
- github.com/stretchr/testify v1.7.4
+ github.com/stretchr/testify v1.7.5
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/ulikunitz/xz v0.5.10
diff --git a/go.sum b/go.sum
index 4440331cd..012d8cd20 100644
--- a/go.sum
+++ b/go.sum
@@ -1280,8 +1280,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
-github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
+github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ=
github.com/sylabs/sif/v2 v2.7.1 h1:XXt9AP39sQfsMCGOGQ/XP9H47yqZOvAonalkaCaNIYM=
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index c3db6152a..471f64b84 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -5,8 +5,10 @@ import (
"fmt"
"net"
"os"
+ "strconv"
"strings"
"sync"
+ "time"
"github.com/containers/common/libnetwork/types"
"github.com/containers/podman/v4/libpod/define"
@@ -63,6 +65,13 @@ type BoltState struct {
// initially created the database. This must match for any further instances
// that access the database, to ensure that state mismatches with
// containers/storage do not occur.
+// - exitCodeBucket/exitCodeTimeStampBucket: (#14559) exit codes must be part
+// of the database to resolve a previous race condition when one process waits
+// for the exit file to be written and another process removes it along with
+// the container during auto-removal. The same race would happen trying to
+// read the exit code from the containers bucket. Hence, exit codes go into
+// their own bucket. To avoid the rather expensive JSON (un)marshaling, we
+// have two buckets: one for the exit codes, the other for the timestamps.
// NewBoltState creates a new bolt-backed state database
func NewBoltState(path string, runtime *Runtime) (State, error) {
@@ -98,6 +107,8 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
allVolsBkt,
execBkt,
runtimeConfigBkt,
+ exitCodeBkt,
+ exitCodeTimeStampBkt,
}
// Does the DB need an update?
@@ -192,6 +203,45 @@ func (s *BoltState) Refresh() error {
return err
}
+ exitCodeBucket, err := getExitCodeBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ timeStampBucket, err := getExitCodeTimeStampBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ // Clear all exec exit codes
+ toRemoveExitCodes := []string{}
+ err = exitCodeBucket.ForEach(func(id, _ []byte) error {
+ toRemoveExitCodes = append(toRemoveExitCodes, string(id))
+ return nil
+ })
+ if err != nil {
+ return errors.Wrapf(err, "error reading exit codes bucket")
+ }
+ for _, id := range toRemoveExitCodes {
+ if err := exitCodeBucket.Delete([]byte(id)); err != nil {
+ return errors.Wrapf(err, "error removing exit code for ID %s", id)
+ }
+ }
+
+ toRemoveTimeStamps := []string{}
+ err = timeStampBucket.ForEach(func(id, _ []byte) error {
+ toRemoveTimeStamps = append(toRemoveTimeStamps, string(id))
+ return nil
+ })
+ if err != nil {
+ return errors.Wrapf(err, "reading timestamps bucket")
+ }
+ for _, id := range toRemoveTimeStamps {
+ if err := timeStampBucket.Delete([]byte(id)); err != nil {
+ return errors.Wrapf(err, "removing timestamp for ID %s", id)
+ }
+ }
+
// Iterate through all IDs. Check if they are containers.
// If they are, unmarshal their state, and then clear
// PID, mountpoint, and state for all of them
@@ -1341,6 +1391,204 @@ func (s *BoltState) GetContainerConfig(id string) (*ContainerConfig, error) {
return config, nil
}
+// AddContainerExitCode adds the exit code for the specified container to the database.
+func (s *BoltState) AddContainerExitCode(id string, exitCode int32) error {
+ if len(id) == 0 {
+ return define.ErrEmptyID
+ }
+
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ rawID := []byte(id)
+ rawExitCode := []byte(strconv.Itoa(int(exitCode)))
+ rawTimeStamp, err := time.Now().MarshalText()
+ if err != nil {
+ return fmt.Errorf("marshaling exit-code time stamp: %w", err)
+ }
+
+ return db.Update(func(tx *bolt.Tx) error {
+ exitCodeBucket, err := getExitCodeBucket(tx)
+ if err != nil {
+ return err
+ }
+ timeStampBucket, err := getExitCodeTimeStampBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ if err := exitCodeBucket.Put(rawID, rawExitCode); err != nil {
+ return fmt.Errorf("adding exit code of container %s to DB: %w", id, err)
+ }
+ if err := timeStampBucket.Put(rawID, rawTimeStamp); err != nil {
+ if rmErr := exitCodeBucket.Delete(rawID); rmErr != nil {
+ logrus.Errorf("Removing exit code of container %s from DB: %v", id, rmErr)
+ }
+ return fmt.Errorf("adding exit-code time stamp of container %s to DB: %w", id, err)
+ }
+
+ return nil
+ })
+}
+
+// GetContainerExitCode returns the exit code for the specified container.
+func (s *BoltState) GetContainerExitCode(id string) (int32, error) {
+ if len(id) == 0 {
+ return -1, define.ErrEmptyID
+ }
+
+ if !s.valid {
+ return -1, define.ErrDBClosed
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return -1, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ rawID := []byte(id)
+ result := int32(-1)
+ return result, db.View(func(tx *bolt.Tx) error {
+ exitCodeBucket, err := getExitCodeBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ rawExitCode := exitCodeBucket.Get(rawID)
+ if rawExitCode == nil {
+ return fmt.Errorf("getting exit code of container %s from DB: %w", id, define.ErrNoSuchExitCode)
+ }
+
+ exitCode, err := strconv.Atoi(string(rawExitCode))
+ if err != nil {
+ return fmt.Errorf("converting raw exit code %v of container %s: %w", rawExitCode, id, err)
+ }
+
+ result = int32(exitCode)
+ return nil
+ })
+}
+
+// GetContainerExitCodeTimeStamp returns the time stamp when the exit code of
+// the specified container was added to the database.
+func (s *BoltState) GetContainerExitCodeTimeStamp(id string) (*time.Time, error) {
+ if len(id) == 0 {
+ return nil, define.ErrEmptyID
+ }
+
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ rawID := []byte(id)
+ var result time.Time
+ return &result, db.View(func(tx *bolt.Tx) error {
+ timeStampBucket, err := getExitCodeTimeStampBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ rawTimeStamp := timeStampBucket.Get(rawID)
+ if rawTimeStamp == nil {
+ return fmt.Errorf("getting exit-code time stamp of container %s from DB: %w", id, define.ErrNoSuchExitCode)
+ }
+
+ if err := result.UnmarshalText(rawTimeStamp); err != nil {
+ return fmt.Errorf("converting raw time stamp %v of container %s from DB: %w", rawTimeStamp, id, err)
+ }
+
+ return nil
+ })
+}
+
+// PruneExitCodes removes exit codes older than 5 minutes.
+func (s *BoltState) PruneContainerExitCodes() error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ toRemoveIDs := []string{}
+
+ threshold := time.Minute * 5
+ err = db.View(func(tx *bolt.Tx) error {
+ timeStampBucket, err := getExitCodeTimeStampBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ return timeStampBucket.ForEach(func(rawID, rawTimeStamp []byte) error {
+ var timeStamp time.Time
+ if err := timeStamp.UnmarshalText(rawTimeStamp); err != nil {
+ return fmt.Errorf("converting raw time stamp %v of container %s from DB: %w", rawTimeStamp, string(rawID), err)
+ }
+ if time.Since(timeStamp) > threshold {
+ toRemoveIDs = append(toRemoveIDs, string(rawID))
+ }
+ return nil
+ })
+ })
+ if err != nil {
+ return errors.Wrapf(err, "reading exit codes to prune")
+ }
+
+ if len(toRemoveIDs) > 0 {
+ err = db.Update(func(tx *bolt.Tx) error {
+ exitCodeBucket, err := getExitCodeBucket(tx)
+ if err != nil {
+ return err
+ }
+ timeStampBucket, err := getExitCodeTimeStampBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ var finalErr error
+ for _, id := range toRemoveIDs {
+ rawID := []byte(id)
+ if err := exitCodeBucket.Delete(rawID); err != nil {
+ if finalErr != nil {
+ logrus.Error(finalErr)
+ }
+ finalErr = fmt.Errorf("removing exit code of container %s from DB: %w", id, err)
+ }
+ if err := timeStampBucket.Delete(rawID); err != nil {
+ if finalErr != nil {
+ logrus.Error(finalErr)
+ }
+ finalErr = fmt.Errorf("removing exit code timestamp of container %s from DB: %w", id, err)
+ }
+ }
+
+ return finalErr
+ })
+ if err != nil {
+ return errors.Wrapf(err, "pruning exit codes")
+ }
+ }
+
+ return nil
+}
+
// AddExecSession adds an exec session to the state.
func (s *BoltState) AddExecSession(ctr *Container, session *ExecSession) error {
if !s.valid {
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index d6f035af9..edba78d6d 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -29,6 +29,9 @@ const (
aliasesName = "aliases"
runtimeConfigName = "runtime-config"
+ exitCodeName = "exit-code"
+ exitCodeTimeStampName = "exit-code-time-stamp"
+
configName = "config"
stateName = "state"
dependenciesName = "dependencies"
@@ -65,6 +68,9 @@ var (
volDependenciesBkt = []byte(volCtrDependencies)
networksBkt = []byte(networksName)
+ exitCodeBkt = []byte(exitCodeName)
+ exitCodeTimeStampBkt = []byte(exitCodeTimeStampName)
+
configKey = []byte(configName)
stateKey = []byte(stateName)
netNSKey = []byte(netNSName)
@@ -362,6 +368,22 @@ func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
return bkt, nil
}
+func getExitCodeBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
+ bkt := tx.Bucket(exitCodeBkt)
+ if bkt == nil {
+ return nil, errors.Wrapf(define.ErrDBBadConfig, "exit-code container bucket not found in DB")
+ }
+ return bkt, nil
+}
+
+func getExitCodeTimeStampBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
+ bkt := tx.Bucket(exitCodeTimeStampBkt)
+ if bkt == nil {
+ return nil, errors.Wrapf(define.ErrDBBadConfig, "exit-code time stamp bucket not found in DB")
+ }
+ return bkt, nil
+}
+
func (s *BoltState) getContainerConfigFromDB(id []byte, config *ContainerConfig, ctrsBkt *bolt.Bucket) error {
ctrBkt := ctrsBkt.Bucket(id)
if ctrBkt == nil {
diff --git a/libpod/container.go b/libpod/container.go
index 04a4ae64a..3a15cfbdb 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -518,7 +518,7 @@ func (c *Container) PortMappings() ([]types.PortMapping, error) {
if len(c.config.NetNsCtr) > 0 {
netNsCtr, err := c.runtime.GetContainer(c.config.NetNsCtr)
if err != nil {
- return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
+ return nil, errors.Wrapf(err, "unable to look up network namespace for container %s", c.ID())
}
return netNsCtr.PortMappings()
}
@@ -657,7 +657,7 @@ func (c *Container) Hostname() string {
utsNsCtr, err := c.runtime.GetContainer(c.config.UTSNsCtr)
if err != nil {
// should we return an error here?
- logrus.Errorf("unable to lookup uts namespace for container %s: %v", c.ID(), err)
+ logrus.Errorf("unable to look up uts namespace for container %s: %v", c.ID(), err)
return ""
}
return utsNsCtr.Hostname()
diff --git a/libpod/container_api.go b/libpod/container_api.go
index b064d3528..c14fe95b0 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -2,6 +2,7 @@ package libpod
import (
"context"
+ "fmt"
"io"
"io/ioutil"
"net/http"
@@ -490,41 +491,84 @@ func (c *Container) RemoveArtifact(name string) error {
// Wait blocks until the container exits and returns its exit code.
func (c *Container) Wait(ctx context.Context) (int32, error) {
- return c.WaitWithInterval(ctx, DefaultWaitInterval)
+ return c.WaitForExit(ctx, DefaultWaitInterval)
}
-// WaitWithInterval blocks until the container to exit and returns its exit
-// code. The argument is the interval at which checks the container's status.
-func (c *Container) WaitWithInterval(ctx context.Context, waitTimeout time.Duration) (int32, error) {
+// WaitForExit blocks until the container exits and returns its exit code. The
+// argument is the interval at which checks the container's status.
+func (c *Container) WaitForExit(ctx context.Context, pollInterval time.Duration) (int32, error) {
if !c.valid {
return -1, define.ErrCtrRemoved
}
- exitFile, err := c.exitFilePath()
- if err != nil {
- return -1, err
- }
- chWait := make(chan error, 1)
+ id := c.ID()
+ var conmonTimer time.Timer
+ conmonTimerSet := false
- go func() {
- <-ctx.Done()
- chWait <- define.ErrCanceled
- }()
+ getExitCode := func() (bool, int32, error) {
+ containerRemoved := false
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ }
- for {
- // ignore errors here (with exception of cancellation), it is only used to avoid waiting
- // too long.
- _, e := WaitForFile(exitFile, chWait, waitTimeout)
- if e == define.ErrCanceled {
- return -1, define.ErrCanceled
+ if err := c.syncContainer(); err != nil {
+ if !errors.Is(err, define.ErrNoSuchCtr) {
+ return false, -1, err
+ }
+ containerRemoved = true
+ }
+
+ // If conmon is not alive anymore set a timer to make sure
+ // we're returning even if conmon has forcefully been killed.
+ if !conmonTimerSet && !containerRemoved {
+ conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
+ switch {
+ case errors.Is(err, define.ErrNoSuchCtr):
+ containerRemoved = true
+ case err != nil:
+ return false, -1, err
+ case !conmonAlive:
+ timerDuration := time.Second * 20
+ conmonTimer = *time.NewTimer(timerDuration)
+ conmonTimerSet = true
+ }
+ }
+
+ if !containerRemoved {
+ // If conmon is dead for more than $timerDuration or if the
+ // container has exited properly, try to look up the exit code.
+ select {
+ case <-conmonTimer.C:
+ logrus.Debugf("Exceeded conmon timeout waiting for container %s to exit", id)
+ default:
+ if !c.ensureState(define.ContainerStateExited, define.ContainerStateConfigured) {
+ return false, -1, nil
+ }
+ }
}
- stopped, code, err := c.isStopped()
+ exitCode, err := c.runtime.state.GetContainerExitCode(id)
+ if err != nil {
+ return true, -1, err
+ }
+
+ return true, exitCode, nil
+ }
+
+ for {
+ hasExited, exitCode, err := getExitCode()
+ if hasExited {
+ return exitCode, err
+ }
if err != nil {
return -1, err
}
- if stopped {
- return code, nil
+ select {
+ case <-ctx.Done():
+ return -1, fmt.Errorf("waiting for exit code of container %s canceled", id)
+ default:
+ time.Sleep(pollInterval)
}
}
}
@@ -551,11 +595,12 @@ func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeou
wantedStates := make(map[define.ContainerStatus]bool, len(conditions))
for _, condition := range conditions {
- if condition == define.ContainerStateStopped || condition == define.ContainerStateExited {
+ switch condition {
+ case define.ContainerStateExited, define.ContainerStateStopped:
waitForExit = true
- continue
+ default:
+ wantedStates[condition] = true
}
- wantedStates[condition] = true
}
trySend := func(code int32, err error) {
@@ -572,7 +617,7 @@ func (c *Container) WaitForConditionWithInterval(ctx context.Context, waitTimeou
go func() {
defer wg.Done()
- code, err := c.WaitWithInterval(ctx, waitTimeout)
+ code, err := c.WaitForExit(ctx, waitTimeout)
trySend(code, err)
}()
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index fd451f9ef..ae61298f3 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -219,7 +219,7 @@ func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error {
// Write an event for the container's death
c.newContainerExitedEvent(c.state.ExitCode)
- return nil
+ return c.runtime.state.AddContainerExitCode(c.ID(), c.state.ExitCode)
}
func (c *Container) shouldRestart() bool {
@@ -290,7 +290,7 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err
return false, err
}
- // setup slirp4netns again because slirp4netns will die when conmon exits
+ // set up slirp4netns again because slirp4netns will die when conmon exits
if c.config.NetMode.IsSlirp4netns() {
err := c.runtime.setupSlirp4netns(c, c.state.NetNS)
if err != nil {
@@ -298,7 +298,7 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err
}
}
- // setup rootlesskit port forwarder again since it dies when conmon exits
+ // set up rootlesskit port forwarder again since it dies when conmon exits
// we use rootlesskit port forwarder only as rootless and when bridge network is used
if rootless.IsRootless() && c.config.NetMode.IsBridge() && len(c.config.PortMappings) > 0 {
err := c.runtime.setupRootlessPortMappingViaRLK(c, c.state.NetNS.Path(), c.state.NetworkStatus)
@@ -589,7 +589,7 @@ func (c *Container) teardownStorage() error {
}
if err := c.cleanupStorage(); err != nil {
- return errors.Wrapf(err, "failed to cleanup container %s storage", c.ID())
+ return errors.Wrapf(err, "failed to clean up container %s storage", c.ID())
}
if err := c.runtime.storageService.DeleteContainer(c.ID()); err != nil {
@@ -784,20 +784,6 @@ func (c *Container) getArtifactPath(name string) string {
return filepath.Join(c.config.StaticDir, artifactsDir, name)
}
-// Used with Wait() to determine if a container has exited
-func (c *Container) isStopped() (bool, int32, error) {
- if !c.batched {
- c.lock.Lock()
- defer c.lock.Unlock()
- }
- err := c.syncContainer()
- if err != nil {
- return true, -1, err
- }
-
- return !c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopping), c.state.ExitCode, nil
-}
-
// save container state to the database
func (c *Container) save() error {
if err := c.runtime.state.SaveContainer(c); err != nil {
@@ -1282,13 +1268,6 @@ func (c *Container) stop(timeout uint) error {
}
}
- // Check if conmon is still alive.
- // If it is not, we won't be getting an exit file.
- conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
- if err != nil {
- return err
- }
-
// Set the container state to "stopping" and unlock the container
// before handing it over to conmon to unblock other commands. #8501
// demonstrates nicely that a high stop timeout will block even simple
@@ -1341,21 +1320,18 @@ func (c *Container) stop(timeout uint) error {
}
c.newContainerEvent(events.Stop)
-
- c.state.PID = 0
- c.state.ConmonPID = 0
c.state.StoppedByUser = true
+ conmonAlive, err := c.ociRuntime.CheckConmonRunning(c)
+ if err != nil {
+ return err
+ }
if !conmonAlive {
- // Conmon is dead, so we can't expect an exit code.
- c.state.ExitCode = -1
- c.state.FinishedTime = time.Now()
- c.state.State = define.ContainerStateStopped
- if err := c.save(); err != nil {
- logrus.Errorf("Saving container %s status: %v", c.ID(), err)
+ if err := c.checkExitFile(); err != nil {
+ return err
}
- return errors.Wrapf(define.ErrConmonDead, "container %s conmon process missing, cannot retrieve exit code", c.ID())
+ return c.save()
}
if err := c.save(); err != nil {
@@ -1784,7 +1760,7 @@ func (c *Container) cleanupStorage() error {
overlayBasePath := filepath.Dir(c.state.Mountpoint)
if err := overlay.Unmount(overlayBasePath); err != nil {
if cleanupErr != nil {
- logrus.Errorf("Failed to cleanup overlay mounts for %s: %v", c.ID(), err)
+ logrus.Errorf("Failed to clean up overlay mounts for %s: %v", c.ID(), err)
}
cleanupErr = err
}
@@ -1801,7 +1777,7 @@ func (c *Container) cleanupStorage() error {
if err := c.cleanupOverlayMounts(); err != nil {
// If the container can't remove content report the error
- logrus.Errorf("Failed to cleanup overlay mounts for %s: %v", c.ID(), err)
+ logrus.Errorf("Failed to clean up overlay mounts for %s: %v", c.ID(), err)
cleanupErr = err
}
@@ -1880,7 +1856,7 @@ func (c *Container) cleanup(ctx context.Context) error {
// we cannot use the dependency container lock due ABBA deadlocks
if lock, err := lockfile.GetLockfile(hoststFile); err == nil {
lock.Lock()
- // make sure to ignore ENOENT error in case the netns container was cleanup before this one
+ // make sure to ignore ENOENT error in case the netns container was cleaned up before this one
if err := etchosts.Remove(hoststFile, getLocalhostHostEntry(c)); err != nil && !errors.Is(err, os.ErrNotExist) {
// this error is not fatal we still want to do proper cleanup
logrus.Errorf("failed to remove hosts entry from the netns containers /etc/hosts: %v", err)
@@ -1939,6 +1915,18 @@ func (c *Container) cleanup(ctx context.Context) error {
}
}
+ // Prune the exit codes of other container during clean up.
+ // Since Podman is no daemon, we have to clean them up somewhere.
+ // Cleanup seems like a good place as it's not performance
+ // critical.
+ if err := c.runtime.state.PruneContainerExitCodes(); err != nil {
+ if lastError == nil {
+ lastError = err
+ } else {
+ logrus.Errorf("Pruning container exit codes: %v", err)
+ }
+ }
+
return lastError
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 245fb587d..77b598b16 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -311,7 +311,7 @@ func (c *Container) cleanupNetwork() error {
// Stop the container's network namespace (if it has one)
if err := c.runtime.teardownNetNS(c); err != nil {
- logrus.Errorf("Unable to cleanup network for container %s: %q", c.ID(), err)
+ logrus.Errorf("Unable to clean up network for container %s: %q", c.ID(), err)
}
c.state.NetNS = nil
@@ -1210,7 +1210,7 @@ func (c *Container) createCheckpointImage(ctx context.Context, options Container
if err != nil {
return err
}
- // Clean-up buildah working container
+ // Clean up buildah working container
defer func() {
if err := importBuilder.Delete(); err != nil {
logrus.Errorf("Image builder delete failed: %v", err)
@@ -1504,7 +1504,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
c.state.Restored = false
c.state.RestoredTime = time.Time{}
- // Cleanup Storage and Network
+ // Clean up Storage and Network
if err := c.cleanup(ctx); err != nil {
return nil, 0, err
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index f5a7c73e5..9757a85b1 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -24,6 +24,10 @@ var (
// not exist.
ErrNoSuchExecSession = errors.New("no such exec session")
+ // ErrNoSuchExitCode indicates that the requested container exit code
+ // does not exist.
+ ErrNoSuchExitCode = errors.New("no such exit code")
+
// ErrDepExists indicates that the current object has dependencies and
// cannot be removed before them.
ErrDepExists = errors.New("dependency exists")
diff --git a/libpod/events.go b/libpod/events.go
index f09d8402a..021b3b53c 100644
--- a/libpod/events.go
+++ b/libpod/events.go
@@ -151,6 +151,9 @@ func (r *Runtime) GetEvents(ctx context.Context, filters []string) ([]*events.Ev
// GetLastContainerEvent takes a container name or ID and an event status and returns
// the last occurrence of the container event
func (r *Runtime) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
+ // FIXME: events should be read in reverse order!
+ // https://github.com/containers/podman/issues/14579
+
// check to make sure the event.Status is valid
if _, err := events.StringToStatus(containerEvent.String()); err != nil {
return nil, err
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index 40af9aec3..bd77e98c6 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -26,7 +26,7 @@ const (
func (r *Runtime) HealthCheck(name string) (define.HealthCheckStatus, error) {
container, err := r.LookupContainer(name)
if err != nil {
- return define.HealthCheckContainerNotFound, errors.Wrapf(err, "unable to lookup %s to perform a health check", name)
+ return define.HealthCheckContainerNotFound, errors.Wrapf(err, "unable to look up %s to perform a health check", name)
}
hcStatus, err := checkHealthCheckCanBeRun(container)
if err == nil {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index cb1547a93..a83423c9f 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -291,7 +291,7 @@ func (r *RootlessNetNS) Do(toRun func() error) error {
return err
}
-// Cleanup the rootless network namespace if needed.
+// Clean up the rootless network namespace if needed.
// It checks if we have running containers with the bridge network mode.
// Cleanup() expects that r.Lock is locked
func (r *RootlessNetNS) Cleanup(runtime *Runtime) error {
@@ -783,7 +783,7 @@ func (r *Runtime) teardownNetwork(ns string, opts types.NetworkOptions) error {
// execute the cni setup in the rootless net ns
err = rootlessNetNS.Do(tearDownPod)
if cerr := rootlessNetNS.Cleanup(r); cerr != nil {
- logrus.WithError(err).Error("failed to cleanup rootless netns")
+ logrus.WithError(err).Error("failed to clean up rootless netns")
}
rootlessNetNS.Lock.Unlock()
} else {
diff --git a/libpod/oci_conmon_attach_linux.go b/libpod/oci_conmon_attach_linux.go
index 155a8fbc3..26f9ba083 100644
--- a/libpod/oci_conmon_attach_linux.go
+++ b/libpod/oci_conmon_attach_linux.go
@@ -120,7 +120,7 @@ func (r *ConmonOCIRuntime) Attach(c *Container, params *AttachOptions) error {
// conmon will then send the exit code of the exec process, or an error in the exec session
// startFd must be the input side of the fd.
// newSize resizes the tty to this size before the process is started, must be nil if the exec session has no tty
-// conmon will wait to start the exec session until the parent process has setup the console socket.
+// conmon will wait to start the exec session until the parent process has set up the console socket.
// Once attachToExec successfully attaches to the console socket, the child conmon process responsible for calling runtime exec
// will read from the output side of start fd, thus learning to start the child process.
// Thus, the order goes as follow:
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index fde8624b0..d417626dc 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -264,11 +264,6 @@ func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *Conta
// status, but will instead only check for the existence of the conmon exit file
// and update state to stopped if it exists.
func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
- exitFile, err := r.ExitFilePath(ctr)
- if err != nil {
- return err
- }
-
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return err
@@ -340,22 +335,10 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
// Only grab exit status if we were not already stopped
// If we were, it should already be in the database
if ctr.state.State == define.ContainerStateStopped && oldState != define.ContainerStateStopped {
- var fi os.FileInfo
- chWait := make(chan error)
- defer close(chWait)
-
- _, err := WaitForFile(exitFile, chWait, time.Second*5)
- if err == nil {
- fi, err = os.Stat(exitFile)
+ if _, err := ctr.Wait(context.Background()); err != nil {
+ logrus.Errorf("Waiting for container %s to exit: %v", ctr.ID(), err)
}
- if err != nil {
- ctr.state.ExitCode = -1
- ctr.state.FinishedTime = time.Now()
- logrus.Errorf("No exit file for container %s found: %v", ctr.ID(), err)
- return nil
- }
-
- return ctr.handleExitFile(exitFile, fi)
+ return nil
}
// Handle ContainerStateStopping - keep it unless the container
@@ -1166,7 +1149,6 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}).Debugf("running conmon: %s", r.conmonPath)
cmd := exec.Command(r.conmonPath, args...)
- cmd.Dir = ctr.bundlePath()
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
@@ -1354,8 +1336,6 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
logDriverArg = define.NoLogging
case define.PassthroughLogging:
logDriverArg = define.PassthroughLogging
- case define.JSONLogging:
- fallthrough
//lint:ignore ST1015 the default case has to be here
default: //nolint:stylecheck,gocritic
// No case here should happen except JSONLogging, but keep this here in case the options are extended
@@ -1365,6 +1345,8 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
// to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod
// since the former case is obscure, and the latter case isn't an error, let's silently fallthrough
fallthrough
+ case define.JSONLogging:
+ fallthrough
case define.KubernetesLogging:
logDriverArg = fmt.Sprintf("%s:%s", define.KubernetesLogging, logPath)
}
diff --git a/libpod/options.go b/libpod/options.go
index 8b3b07efa..9a29fb279 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1812,7 +1812,7 @@ func WithHostDevice(dev []specs.LinuxDevice) CtrCreateOption {
}
}
-// WithSelectedPasswordManagement makes it so that the container either does or does not setup /etc/passwd or /etc/group
+// WithSelectedPasswordManagement makes it so that the container either does or does not set up /etc/passwd or /etc/group
func WithSelectedPasswordManagement(passwd *bool) CtrCreateOption {
return func(c *Container) error {
if c.valid {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 6c8a99846..11ec750b1 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -135,7 +135,7 @@ func SetXdgDirs() error {
return nil
}
- // Setup XDG_RUNTIME_DIR
+ // Set up XDG_RUNTIME_DIR
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDir == "" {
@@ -156,7 +156,7 @@ func SetXdgDirs() error {
}
}
- // Setup XDG_CONFIG_HOME
+ // Set up XDG_CONFIG_HOME
if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" {
cfgHomeDir, err := util.GetRootlessConfigHomeDir()
if err != nil {
@@ -450,7 +450,7 @@ func makeRuntime(runtime *Runtime) (retErr error) {
}
}()
- // Setup the eventer
+ // Set up the eventer
eventer, err := runtime.newEventer()
if err != nil {
return err
@@ -539,7 +539,7 @@ func makeRuntime(runtime *Runtime) (retErr error) {
}
}
- // the store is only setup when we are in the userns so we do the same for the network interface
+ // the store is only set up when we are in the userns so we do the same for the network interface
if !needsUserns {
netBackend, netInterface, err := network.NetworkBackend(runtime.store, runtime.config, runtime.syslog)
if err != nil {
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index bdfc102ba..a9ae9d1db 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -755,7 +755,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo
if cleanupErr == nil {
cleanupErr = err
} else {
- logrus.Errorf("Cleanup storage: %v", err)
+ logrus.Errorf("Cleaning up storage: %v", err)
}
}
@@ -810,11 +810,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo
// Ignore error, since podman will report original error
volumesFrom, _ := c.volumesFrom()
if len(volumesFrom) > 0 {
- logrus.Debugf("Cleanup volume not possible since volume is in use (%s)", v)
+ logrus.Debugf("Cleaning up volume not possible since volume is in use (%s)", v)
continue
}
}
- logrus.Errorf("Cleanup volume (%s): %v", v, err)
+ logrus.Errorf("Cleaning up volume (%s): %v", v, err)
}
}
}
@@ -964,7 +964,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol
continue
}
if err := r.removeVolume(ctx, volume, false, timeout); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed {
- logrus.Errorf("Cleanup volume (%s): %v", v, err)
+ logrus.Errorf("Cleaning up volume (%s): %v", v, err)
}
}
}
@@ -1111,7 +1111,7 @@ func (r *Runtime) GetContainersByList(containers []string) ([]*Container, error)
for _, inputContainer := range containers {
ctr, err := r.LookupContainer(inputContainer)
if err != nil {
- return ctrs, errors.Wrapf(err, "unable to lookup container %s", inputContainer)
+ return ctrs, errors.Wrapf(err, "unable to look up container %s", inputContainer)
}
ctrs = append(ctrs, ctr)
}
diff --git a/libpod/state.go b/libpod/state.go
index 471023769..4fbd3c302 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -111,6 +111,15 @@ type State interface {
// Return a container config from the database by full ID
GetContainerConfig(id string) (*ContainerConfig, error)
+ // Add the exit code for the specified container to the database.
+ AddContainerExitCode(id string, exitCode int32) error
+
+ // Return the exit code for the specified container.
+ GetContainerExitCode(id string) (int32, error)
+
+ // Remove exit codes older than 5 minutes.
+ PruneContainerExitCodes() error
+
// Add creates a reference to an exec session in the database.
// The container the exec session is attached to will be recorded.
// The container state will not be modified.
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go
index 66743ce06..d6bc26416 100644
--- a/pkg/api/handlers/compat/containers_stats.go
+++ b/pkg/api/handlers/compat/containers_stats.go
@@ -58,7 +58,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
flusher.Flush()
}
- // Setup JSON encoder for streaming.
+ // Set up JSON encoder for streaming.
coder.SetEscapeHTML(true)
var preRead time.Time
var preCPUStats CPUStats
diff --git a/pkg/api/handlers/libpod/containers_stats.go b/pkg/api/handlers/libpod/containers_stats.go
index d34254fd7..46d722a3d 100644
--- a/pkg/api/handlers/libpod/containers_stats.go
+++ b/pkg/api/handlers/libpod/containers_stats.go
@@ -66,7 +66,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
flusher.Flush()
}
- // Setup JSON encoder for streaming.
+ // Set up JSON encoder for streaming.
coder := json.NewEncoder(w)
coder.SetEscapeHTML(true)
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 8588b49ba..1795f6ce1 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -191,7 +191,6 @@ func waitDockerCondition(ctx context.Context, containerName string, interval tim
var notRunningStates = []define.ContainerStatus{
define.ContainerStateCreated,
define.ContainerStateRemoving,
- define.ContainerStateStopped,
define.ContainerStateExited,
define.ContainerStateConfigured,
}
diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go
index 2d02df7dc..aaaf6688e 100644
--- a/pkg/api/server/listener_api.go
+++ b/pkg/api/server/listener_api.go
@@ -11,7 +11,7 @@ import (
// ListenUnix follows stdlib net.Listen() API, providing a unix listener for given path
// ListenUnix will delete and create files/directories as needed
func ListenUnix(network string, path string) (net.Listener, error) {
- // setup custom listener for API server
+ // set up custom listener for API server
err := os.MkdirAll(filepath.Dir(path), 0770)
if err != nil {
return nil, errors.Wrapf(err, "api.ListenUnix() failed to create %s", filepath.Dir(path))
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index b418b8430..6b3576f31 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -95,7 +95,7 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string)
return nil, errors.Wrapf(err, "Value of CONTAINER_HOST is not a valid url: %s", uri)
}
- // Now we setup the http Client to use the connection above
+ // Now we set up the http Client to use the connection above
var connection Connection
switch _url.Scheme {
case "ssh":
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index c7cd0cb56..281e448f6 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -16,7 +16,6 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
- "github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/libpod/logs"
"github.com/containers/podman/v4/pkg/checkpoint"
"github.com/containers/podman/v4/pkg/domain/entities"
@@ -38,7 +37,7 @@ import (
)
// getContainersAndInputByContext gets containers whether all, latest, or a slice of names/ids
-// is specified. It also returns a list of the corresponding input name used to lookup each container.
+// is specified. It also returns a list of the corresponding input name used to look up each container.
func getContainersAndInputByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) {
var ctr *libpod.Container
ctrs = []*libpod.Container{}
@@ -183,7 +182,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
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 to cleanup since we do not know if the other cleanup process is successful
+ // 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
}
@@ -488,7 +487,7 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To
container, err = ic.Libpod.LookupContainer(options.NameOrID)
}
if err != nil {
- return nil, errors.Wrap(err, "unable to lookup requested container")
+ return nil, errors.Wrap(err, "unable to look up requested container")
}
// Run Top.
@@ -635,13 +634,13 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
containers, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
default:
for _, nameOrID := range namesOrIds {
- logrus.Debugf("lookup container: %q", nameOrID)
+ logrus.Debugf("look up container: %q", nameOrID)
ctr, err := ic.Libpod.LookupContainer(nameOrID)
if err == nil {
containers = append(containers, ctr)
} else {
// If container was not found, check if this is a checkpoint image
- logrus.Debugf("lookup image: %q", nameOrID)
+ logrus.Debugf("look up image: %q", nameOrID)
img, _, err := ic.Libpod.LibimageRuntime().LookupImage(nameOrID, nil)
if err != nil {
return nil, fmt.Errorf("no such container or image: %s", nameOrID)
@@ -939,6 +938,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
}
return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID())
}
+
exitCode = ic.GetContainerExitCode(ctx, ctr)
reports = append(reports, &entities.ContainerStartReport{
Id: ctr.ID(),
@@ -1099,25 +1099,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
func (ic *ContainerEngine) GetContainerExitCode(ctx context.Context, ctr *libpod.Container) int {
exitCode, err := ctr.Wait(ctx)
- if err == nil {
- return int(exitCode)
- }
- if errors.Cause(err) != define.ErrNoSuchCtr {
- logrus.Errorf("Could not retrieve exit code: %v", err)
+ if err != nil {
+ logrus.Errorf("Waiting for container %s: %v", ctr.ID(), err)
return define.ExecErrorCodeNotFound
}
- // Make 4 attempt with 0.25s backoff between each for 1 second total
- var event *events.Event
- for i := 0; i < 4; i++ {
- event, err = ic.Libpod.GetLastContainerEvent(ctx, ctr.ID(), events.Exited)
- if err != nil {
- time.Sleep(250 * time.Millisecond)
- continue
- }
- return event.ContainerExitCode
- }
- logrus.Errorf("Could not retrieve exit code from event: %v", err)
- return define.ExecErrorCodeNotFound
+ return int(exitCode)
}
func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
@@ -1194,12 +1180,12 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
var timeout *uint
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout)
if err != nil {
- report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
+ report.RmErr = errors.Wrapf(err, "failed to clean up and remove container %v", ctr.ID())
}
} else {
err := ctr.Cleanup(ctx)
if err != nil {
- report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
+ report.CleanErr = errors.Wrapf(err, "failed to clean up container %v", ctr.ID())
}
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 8638f4783..3e9cb7f5e 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -393,7 +393,7 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp
pod, err = ic.Libpod.LookupPod(options.NameOrID)
}
if err != nil {
- return nil, errors.Wrap(err, "unable to lookup requested container")
+ return nil, errors.Wrap(err, "unable to look up requested container")
}
// Run Top.
@@ -494,7 +494,7 @@ func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodI
pod, err = ic.Libpod.LookupPod(options.NameOrID)
}
if err != nil {
- return nil, errors.Wrap(err, "unable to lookup requested container")
+ return nil, errors.Wrap(err, "unable to look up requested container")
}
inspect, err := pod.Inspect()
if err != nil {
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 6be37c87f..6e26026d4 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -404,9 +404,9 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options e
}
// Make sure to unlock, unshare can run for a long time.
rootlessNetNS.Lock.Unlock()
- // We do not want to cleanup the netns after unshare.
- // The problem is that we cannot know if we need to cleanup and
- // secondly unshare should allow user to setup the namespace with
+ // We do not want to clean up the netns after unshare.
+ // The problem is that we cannot know if we need to clean up and
+ // secondly unshare should allow user to set up the namespace with
// special things, e.g. potentially macvlan or something like that.
return rootlessNetNS.Do(unshare)
}
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index 03e7ffb5d..162025969 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -342,7 +342,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
options.HostUIDMapping = false
options.HostGIDMapping = false
- // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op
+ // Simply ignore the setting and do not set up an inner namespace for root as it is a no-op
return &options, nil
}
@@ -394,7 +394,7 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
// StartWatcher starts a new SIGHUP go routine for the current config.
func StartWatcher(rt *libpod.Runtime) {
- // Setup the signal notifier
+ // Set up the signal notifier
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGHUP)
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 5b14fac37..6c043465c 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -20,7 +20,7 @@ func getContainersByContext(contextWithConnection context.Context, all, ignore b
func getContainersAndInputByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, []string, error) {
if all && len(namesOrIDs) > 0 {
- return nil, nil, errors.New("cannot lookup containers and all")
+ return nil, nil, errors.New("cannot look up containers and all")
}
options := new(containers.ListOptions).WithAll(true).WithSync(true)
allContainers, err := containers.List(contextWithConnection, options)
@@ -77,7 +77,7 @@ func getContainersAndInputByContext(contextWithConnection context.Context, all,
func getPodsByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]*entities.ListPodsReport, error) {
if all && len(namesOrIDs) > 0 {
- return nil, errors.New("cannot lookup specific pods and all")
+ return nil, errors.New("cannot look up specific pods and all")
}
allPods, err := pods.List(contextWithConnection, nil)
diff --git a/pkg/machine/e2e/list_test.go b/pkg/machine/e2e/list_test.go
index 1c8c6ac81..e2121e7bf 100644
--- a/pkg/machine/e2e/list_test.go
+++ b/pkg/machine/e2e/list_test.go
@@ -29,7 +29,7 @@ var _ = Describe("podman machine list", func() {
firstList, err := mb.setCmd(list).run()
Expect(err).NotTo(HaveOccurred())
Expect(firstList).Should(Exit(0))
- Expect(len(firstList.outputToStringSlice())).To(Equal(1)) // just the header
+ Expect(firstList.outputToStringSlice()).To(HaveLen(1)) // just the header
i := new(initMachine)
session, err := mb.setCmd(i.withImagePath(mb.imagePath)).run()
@@ -39,7 +39,7 @@ var _ = Describe("podman machine list", func() {
secondList, err := mb.setCmd(list).run()
Expect(err).NotTo(HaveOccurred())
Expect(secondList).To(Exit(0))
- Expect(len(secondList.outputToStringSlice())).To(Equal(2)) // one machine and the header
+ Expect(secondList.outputToStringSlice()).To(HaveLen(2)) // one machine and the header
})
It("list machines with quiet or noheading", func() {
@@ -51,12 +51,12 @@ var _ = Describe("podman machine list", func() {
firstList, err := mb.setCmd(list.withQuiet()).run()
Expect(err).NotTo(HaveOccurred())
Expect(firstList).Should(Exit(0))
- Expect(len(firstList.outputToStringSlice())).To(Equal(0)) // No header with quiet
+ Expect(firstList.outputToStringSlice()).To(HaveLen(0)) // No header with quiet
noheaderSession, err := mb.setCmd(list.withNoHeading()).run() // noheader
Expect(err).NotTo(HaveOccurred())
Expect(noheaderSession).Should(Exit(0))
- Expect(len(noheaderSession.outputToStringSlice())).To(Equal(0))
+ Expect(noheaderSession.outputToStringSlice()).To(HaveLen(0))
i := new(initMachine)
session, err := mb.setName(name1).setCmd(i.withImagePath(mb.imagePath)).run()
@@ -70,7 +70,7 @@ var _ = Describe("podman machine list", func() {
secondList, err := mb.setCmd(list.withQuiet()).run()
Expect(err).NotTo(HaveOccurred())
Expect(secondList).To(Exit(0))
- Expect(len(secondList.outputToStringSlice())).To(Equal(2)) // two machines, no header
+ Expect(secondList.outputToStringSlice()).To(HaveLen(2)) // two machines, no header
listNames := secondList.outputToStringSlice()
stripAsterisk(listNames)
@@ -116,10 +116,10 @@ var _ = Describe("podman machine list", func() {
// go format
list := new(listMachine)
- listSession, err := mb.setCmd(list.withFormat("{{.Name}}").withNoHeading()).run()
+ listSession, err := mb.setCmd(list.withFormat("{{.Name}}")).run()
Expect(err).NotTo(HaveOccurred())
Expect(listSession).To(Exit(0))
- Expect(len(listSession.outputToStringSlice())).To(Equal(1))
+ Expect(listSession.outputToStringSlice()).To(HaveLen(1))
listNames := listSession.outputToStringSlice()
stripAsterisk(listNames)
@@ -135,6 +135,15 @@ var _ = Describe("podman machine list", func() {
var listResponse []*machine.ListReporter
err = jsoniter.Unmarshal(listSession.Bytes(), &listResponse)
Expect(err).To(BeNil())
+
+ // table format includes the header
+ list = new(listMachine)
+ listSession3, err3 := mb.setCmd(list.withFormat("table {{.Name}}")).run()
+ Expect(err3).NotTo(HaveOccurred())
+ Expect(listSession3).To(Exit(0))
+ listNames3 := listSession3.outputToStringSlice()
+ Expect(listNames3).To(HaveLen(2))
+ Expect(listNames3).To(ContainSubstring("NAME"))
})
})
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index 35a9a30cb..f4602cc95 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -93,7 +93,7 @@ func NewIgnitionFile(ign DynamicIgnition) error {
tz string
)
// local means the same as the host
- // lookup where it is pointing to on the host
+ // look up where it is pointing to on the host
if ign.TimeZone == "local" {
tz, err = getLocalTimeZone()
if err != nil {
@@ -348,7 +348,7 @@ Delegate=memory pids cpu io
},
})
- // Setup /etc/subuid and /etc/subgid
+ // Set up /etc/subuid and /etc/subgid
for _, sub := range []string{"/etc/subuid", "/etc/subgid"} {
files = append(files, File{
Node: Node{
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 288b2eeb0..5094345ea 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -209,7 +209,7 @@ func migrateVM(configPath string, config []byte, vm *MachineVM) error {
vm.Rootful = old.Rootful
vm.UID = old.UID
- // Backup the original config file
+ // Back up the original config file
if err := os.Rename(configPath, configPath+".orig"); err != nil {
return err
}
@@ -580,7 +580,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
if !errors.Is(err, os.ErrNotExist) {
return err
}
- // lookup qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394
+ // look up qemu again maybe the path was changed, https://github.com/containers/podman/issues/13394
cfg, err := config.Default()
if err != nil {
return err
@@ -1142,7 +1142,7 @@ func (p *Provider) CheckExclusiveActiveVM() (bool, string, error) {
}
// startHostNetworking runs a binary on the host system that allows users
-// to setup port forwarding to the podman virtual machine
+// to set up port forwarding to the podman virtual machine
func (v *MachineVM) startHostNetworking() (string, apiForwardingState, error) {
cfg, err := config.Default()
if err != nil {
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
index c95f8e275..8eacb8da7 100644
--- a/pkg/namespaces/namespaces.go
+++ b/pkg/namespaces/namespaces.go
@@ -112,7 +112,7 @@ func (n UsernsMode) IsDefaultValue() bool {
return n == "" || n == defaultType
}
-// GetAutoOptions returns a AutoUserNsOptions with the settings to setup automatically
+// GetAutoOptions returns a AutoUserNsOptions with the settings to automatically set up
// a user namespace.
func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) {
parts := strings.SplitN(string(n), ":", 2)
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index d0bdf0ffe..fde621b72 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -154,7 +154,7 @@ func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) err
if output, err := cmd.CombinedOutput(); err != nil {
logrus.Errorf("running `%s`: %s", strings.Join(args, " "), output)
- errorStr := fmt.Sprintf("cannot setup namespace using %q", path)
+ errorStr := fmt.Sprintf("cannot set up namespace using %q", path)
if isSet, err := unshare.IsSetID(cmd.Path, mode, cap); err != nil {
logrus.Errorf("Failed to check for %s on %s: %v", idtype, path, err)
} else if !isSet {
@@ -303,7 +303,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ boo
if retErr != nil && pid > 0 {
if err := unix.Kill(pid, unix.SIGKILL); err != nil {
if err != unix.ESRCH {
- logrus.Errorf("Failed to cleanup process %d: %v", pid, err)
+ logrus.Errorf("Failed to clean up process %d: %v", pid, err)
}
}
C.reexec_in_user_namespace_wait(C.int(pid), 0)
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index d552e21ed..e953a1f1f 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -204,7 +204,7 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste
} else {
runRoot = ctr.Runtime().RunRoot()
if runRoot == "" {
- return nil, errors.Errorf("could not lookup container's runroot: got empty string")
+ return nil, errors.Errorf("could not look up container's runroot: got empty string")
}
}
diff --git a/rootless.md b/rootless.md
index 39c961d2a..f5d78b80b 100644
--- a/rootless.md
+++ b/rootless.md
@@ -8,7 +8,7 @@ Contributors are more than welcomed to help with this work. If you decide to ca
* The kernel does not allow processes without CAP_NET_BIND_SERVICE to bind to low ports.
* You can modify the `net.ipv4.ip_unprivileged_port_start` sysctl to change the lowest port. For example `sysctl net.ipv4.ip_unprivileged_port_start=443` allows rootless Podman containers to bind to ports >= 443.
* “How To” documentation is patchy at best.
-* If /etc/subuid and /etc/subgid are not setup for a user, then podman commands
+* If /etc/subuid and /etc/subgid are not set up for a user, then podman commands
can easily fail
* This can be a big issue on machines using Network Based Password information (FreeIPA, Active Directory, LDAP)
* We are working to get support for NSSWITCH on the /etc/subuid and /etc/subgid files.
@@ -24,7 +24,7 @@ can easily fail
* NFS and parallel filesystems enforce file creation on different UIDs on the server side and does not understand User Namespace.
* When a container root process like YUM attempts to create a file owned by a different UID, NFS Server/GPFS denies the creation.
* Does not work with homedirs mounted with noexec/nodev
- * User can setup storage to point to other directories they can write to that are not mounted noexec/nodev
+ * User can set up storage to point to other directories they can write to that are not mounted noexec/nodev
* Support for using native overlayfs as an unprivileged user is only available for Podman version >= 3.1 on a Linux kernel version >= 5.12, otherwise the slower _fuse-overlayfs_ may be used.
* A few Linux distributions (e.g. Ubuntu) have supported even older Podman and Linux kernel versions by modifying the normal Linux kernel behaviour.
* Only other supported driver is VFS.
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 1da199714..1fa67e9ba 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -23,10 +23,31 @@ import (
func getRunString(input []string) []string {
// CRIU does not work with seccomp correctly on RHEL7 : seccomp=unconfined
- runString := []string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()}
+ runString := []string{"run", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()}
return append(runString, input...)
}
+// FIXME FIXME FIXME: workaround for #14653, please remove this function
+// and all calls to it once that bug is fixed.
+func fixmeFixme14653(podmanTest *PodmanTestIntegration, cid string) {
+ if !IsRemote() {
+ // Race condition only affects podman-remote
+ return
+ }
+
+ // Wait for container to truly go away
+ for i := 0; i < 5; i++ {
+ ps := podmanTest.Podman([]string{"container", "exists", cid})
+ ps.WaitWithDefaultTimeout()
+ if ps.ExitCode() == 1 {
+ // yay, it's gone
+ return
+ }
+ time.Sleep(time.Second)
+ }
+ // Fall through. Container still exists, but return anyway.
+}
+
var _ = Describe("Podman checkpoint", func() {
var (
tempdir string
@@ -478,6 +499,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -530,6 +552,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -548,6 +571,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -566,6 +590,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -584,6 +609,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -645,6 +671,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -694,6 +721,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -735,6 +763,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -772,6 +801,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -821,6 +851,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -890,6 +921,7 @@ var _ = Describe("Podman checkpoint", func() {
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1044,6 +1076,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1140,6 +1173,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).To(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
@@ -1252,6 +1286,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1296,6 +1331,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1489,6 +1525,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1573,6 +1610,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1651,6 +1689,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 194d592f4..261db8a9a 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -322,7 +322,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
}
}
- // Setup registries.conf ENV variable
+ // Set up registries.conf ENV variable
p.setDefaultRegistriesConfigEnv()
// Rewrite the PodmanAsUser function
p.PodmanMakeOptions = p.makeOptions
diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go
index 6fd88753b..85cc5023c 100644
--- a/test/e2e/create_staticip_test.go
+++ b/test/e2e/create_staticip_test.go
@@ -25,7 +25,7 @@ var _ = Describe("Podman create with --ip flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
diff --git a/test/e2e/create_staticmac_test.go b/test/e2e/create_staticmac_test.go
index f02d9c88b..32deb04a8 100644
--- a/test/e2e/create_staticmac_test.go
+++ b/test/e2e/create_staticmac_test.go
@@ -25,7 +25,7 @@ var _ = Describe("Podman run with --mac-address flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
diff --git a/test/e2e/image_scp_test.go b/test/e2e/image_scp_test.go
index 2ad3cc75e..53681f05b 100644
--- a/test/e2e/image_scp_test.go
+++ b/test/e2e/image_scp_test.go
@@ -22,12 +22,10 @@ var _ = Describe("podman image scp", func() {
)
BeforeEach(func() {
-
ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF")
conf, err := ioutil.TempFile("", "containersconf")
- if err != nil {
- panic(err)
- }
+ Expect(err).ToNot(HaveOccurred())
+
os.Setenv("CONTAINERS_CONF", conf.Name())
tempdir, err = CreateTempDirInTempDir()
if err != nil {
@@ -57,7 +55,7 @@ var _ = Describe("podman image scp", func() {
}
scp := podmanTest.Podman([]string{"image", "scp", "FOOBAR"})
scp.WaitWithDefaultTimeout()
- Expect(scp).To(ExitWithError())
+ Expect(scp).Should(ExitWithError())
})
It("podman image scp with proper connection", func() {
@@ -67,27 +65,28 @@ var _ = Describe("podman image scp", func() {
cmd := []string{"system", "connection", "add",
"--default",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
- Expect(session).To(Exit(0))
+ Expect(session).Should(Exit(0))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg.Engine).To(HaveField("ActiveService", "QA"))
+ Expect(cfg.Engine).Should(HaveField("ActiveService", "QA"))
Expect(cfg.Engine.ServiceDestinations).To(HaveKeyWithValue("QA",
config.Destination{
- URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ URI: "ssh://root@podman.test:2222/run/podman/podman.sock",
},
))
scp := podmanTest.Podman([]string{"image", "scp", ALPINE, "QA::"})
- scp.Wait(45)
+ scp.WaitWithDefaultTimeout()
// exit with error because we cannot make an actual ssh connection
// This tests that the input we are given is validated and prepared correctly
- // The error given should either be a missing image (due to testing suite complications) or a i/o timeout on ssh
- Expect(scp).To(ExitWithError())
+ // The error given should either be a missing image (due to testing suite complications) or a no such host timeout on ssh
+ Expect(scp).Should(ExitWithError())
+ Expect(scp.ErrorToString()).Should(ContainSubstring("no such host"))
})
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
index af3f98d4b..09fb4e03c 100644
--- a/test/e2e/run_staticip_test.go
+++ b/test/e2e/run_staticip_test.go
@@ -28,7 +28,7 @@ var _ = Describe("Podman run with --ip flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go
index 2228c23b2..baa31424b 100644
--- a/test/e2e/system_connection_test.go
+++ b/test/e2e/system_connection_test.go
@@ -47,9 +47,7 @@ var _ = Describe("podman system connection", func() {
}
f := CurrentGinkgoTestDescription()
- _, _ = GinkgoWriter.Write(
- []byte(
- fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())))
+ processTestResult(f)
})
Context("without running API service", func() {
@@ -58,7 +56,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
@@ -67,10 +65,10 @@ var _ = Describe("podman system connection", func() {
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg).To(HaveActiveService("QA"))
+ Expect(cfg).Should(HaveActiveService("QA"))
Expect(cfg).Should(VerifyService(
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
"~/.ssh/id_rsa",
))
@@ -82,7 +80,7 @@ var _ = Describe("podman system connection", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(config.ReadCustomConfig()).To(HaveActiveService("QE"))
+ Expect(config.ReadCustomConfig()).Should(HaveActiveService("QE"))
})
It("add UDS", func() {
@@ -141,7 +139,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -155,8 +153,8 @@ var _ = Describe("podman system connection", func() {
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg.Engine.ActiveService).To(BeEmpty())
- Expect(cfg.Engine.ServiceDestinations).To(BeEmpty())
+ Expect(cfg.Engine.ActiveService).Should(BeEmpty())
+ Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty())
}
})
@@ -165,7 +163,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -187,7 +185,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
name,
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
@@ -247,7 +245,7 @@ var _ = Describe("podman system connection", func() {
// podman-remote commands will be executed by ginkgo directly.
SkipIfContainerized("sshd is not available when running in a container")
SkipIfRemote("connection heuristic requires both podman and podman-remote binaries")
- SkipIfNotRootless(fmt.Sprintf("FIXME: setup ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid()))
+ SkipIfNotRootless(fmt.Sprintf("FIXME: set up ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid()))
SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running")
SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running")
})
diff --git a/test/framework/framework.go b/test/framework/framework.go
index 57c6bda2a..26e8bf21c 100644
--- a/test/framework/framework.go
+++ b/test/framework/framework.go
@@ -37,7 +37,7 @@ func NilFunc(f *TestFramework) error {
func (t *TestFramework) Setup() {
// Global initialization for the whole framework goes in here
- // Setup the actual test suite
+ // Set up the actual test suite
gomega.Expect(t.setup(t)).To(gomega.Succeed())
}
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 117d791d6..56cf4f266 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -376,17 +376,7 @@ json-file | f
while read driver do_check; do
msg=$(random_string 15)
run_podman run --name myctr --log-driver $driver $IMAGE echo $msg
-
- # Simple output check
- # Special case: 'json-file' emits a warning, the rest do not
- # ...but with podman-remote the warning is on the server only
- if [[ $do_check == 'f' ]] && ! is_remote; then # 'f' for 'fallback'
- is "${lines[0]}" ".* level=error msg=\"json-file logging specified but not supported. Choosing k8s-file logging instead\"" \
- "Fallback warning emitted"
- is "${lines[1]}" "$msg" "basic output sanity check (driver=$driver)"
- else
- is "$output" "$msg" "basic output sanity check (driver=$driver)"
- fi
+ is "$output" "$msg" "basic output sanity check (driver=$driver)"
# Simply confirm that podman preserved our argument as-is
run_podman inspect --format '{{.HostConfig.LogConfig.Type}}' myctr
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 2ad53620d..fb785177c 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -359,7 +359,7 @@ load helpers
run curl -s $SERVER/index.txt
is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
- # cleanup the container
+ # clean up the container
run_podman rm -t 0 -f $cid
# test that we cannot remove the default network
@@ -549,7 +549,7 @@ load helpers
run curl --max-time 3 -s $SERVER/index.txt
is "$output" "$random_1" "curl 127.0.0.1:/index.txt should still work"
- # cleanup
+ # clean up
run_podman rm -t 0 -f $cid $background_cid
run_podman network rm -t 0 -f $netname $netname2
}
@@ -622,7 +622,7 @@ load helpers
run_podman rm -t 0 -f $cid
done
- # Cleanup network
+ # Clean up network
run_podman network rm -t 0 -f $netname
}
diff --git a/troubleshooting.md b/troubleshooting.md
index 4be925f71..05685c906 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -321,7 +321,7 @@ under `/var/lib/containers/storage`.
# restorecon -R -v /srv/containers
```
-The semanage command above tells SELinux to setup the default labeling of
+The semanage command above tells SELinux to set up the default labeling of
`/srv/containers` to match `/var/lib/containers`. The `restorecon` command
tells SELinux to apply the labels to the actual content.
@@ -387,7 +387,7 @@ error creating build container: Error committing the finished image: error addin
#### Solution
Choose one of the following:
- * Setup containers/storage in a different directory, not on an NFS share.
+ * Set up containers/storage in a different directory, not on an NFS share.
* Create a directory on a local file system.
* Edit `~/.config/containers/containers.conf` and point the `volume_path` option to that local directory. (Copy `/usr/share/containers/containers.conf` if `~/.config/containers/containers.conf` does not exist)
* Otherwise just run Podman as root, via `sudo podman`
diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go
index 3bb22a971..95d8e59da 100644
--- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go
+++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go
@@ -1,6 +1,7 @@
package assert
import (
+ "bytes"
"fmt"
"reflect"
"time"
@@ -32,7 +33,8 @@ var (
stringType = reflect.TypeOf("")
- timeType = reflect.TypeOf(time.Time{})
+ timeType = reflect.TypeOf(time.Time{})
+ bytesType = reflect.TypeOf([]byte{})
)
func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
@@ -323,6 +325,26 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64)
}
+ case reflect.Slice:
+ {
+ // We only care about the []byte type.
+ if !canConvert(obj1Value, bytesType) {
+ break
+ }
+
+ // []byte can be compared!
+ bytesObj1, ok := obj1.([]byte)
+ if !ok {
+ bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte)
+
+ }
+ bytesObj2, ok := obj2.([]byte)
+ if !ok {
+ bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
+ }
+
+ return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true
+ }
}
return compareEqual, false
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9b0e22391..cd7e224b3 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -642,7 +642,7 @@ github.com/spf13/cobra
github.com/spf13/pflag
# github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980
github.com/stefanberger/go-pkcs11uri
-# github.com/stretchr/testify v1.7.4
+# github.com/stretchr/testify v1.7.5
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/require