summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-10-20 14:03:13 +0000
committerGitHub <noreply@github.com>2021-10-20 14:03:13 +0000
commit09aade7816e096550e805869f1300d7198aa8f91 (patch)
tree77ad099aae7e8189eb22bdf2afa40b4651f2384b
parentc15c1540837b25305729bc72d61372098e204151 (diff)
parent46f7d2af189530a1f81d5e0aab5244667846e181 (diff)
downloadpodman-09aade7816e096550e805869f1300d7198aa8f91.tar.gz
podman-09aade7816e096550e805869f1300d7198aa8f91.tar.bz2
podman-09aade7816e096550e805869f1300d7198aa8f91.zip
Merge pull request #12040 from mheon/341_release
Bump to v3.4.1
-rw-r--r--RELEASE_NOTES.md20
-rw-r--r--cmd/podman/common/create.go2
-rw-r--r--cmd/podman/common/create_opts.go13
-rw-r--r--cmd/podman/containers/create.go4
-rw-r--r--cmd/podman/containers/stats.go12
-rw-r--r--cmd/podman/diff/diff.go2
-rwxr-xr-xcontrib/cirrus/pr-should-include-tests12
-rwxr-xr-xcontrib/cirrus/pr-should-include-tests.t2
-rw-r--r--contrib/podmanimage/upstream/Dockerfile3
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-manifest.1.md44
-rw-r--r--docs/source/markdown/podman-run.1.md2
-rw-r--r--docs/source/markdown/podman.1.md2
-rw-r--r--libpod/container_api.go4
-rw-r--r--libpod/container_copy_linux.go2
-rw-r--r--libpod/container_internal_linux.go5
-rw-r--r--libpod/kube.go25
-rw-r--r--libpod/oci_attach_linux.go17
-rw-r--r--libpod/oci_conmon_exec_linux.go7
-rw-r--r--libpod/oci_conmon_linux.go10
-rw-r--r--pkg/bindings/containers/attach.go14
-rw-r--r--pkg/bindings/images/build.go5
-rw-r--r--pkg/bindings/test/fixture/Containerfile1
-rw-r--r--pkg/bindings/test/images_test.go100
-rw-r--r--pkg/cgroups/cgroups.go12
-rw-r--r--pkg/domain/infra/abi/containers.go9
-rw-r--r--pkg/hooks/docs/oci-hooks.5.md2
-rw-r--r--pkg/machine/pull.go2
-rw-r--r--pkg/machine/qemu/machine.go16
-rw-r--r--pkg/ps/ps.go6
-rw-r--r--pkg/specgen/generate/kube/kube.go2
-rw-r--r--pkg/specgen/generate/validate.go3
-rw-r--r--test/apiv2/20-containers.at18
-rw-r--r--test/e2e/checkpoint_test.go41
-rw-r--r--test/e2e/generate_kube_test.go113
-rw-r--r--test/e2e/play_kube_test.go41
-rw-r--r--test/system/030-run.bats6
-rw-r--r--test/system/260-sdnotify.bats6
-rw-r--r--test/system/270-socket-activation.bats47
-rw-r--r--version/version.go2
41 files changed, 458 insertions, 180 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index ef48df291..cca300f07 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,25 @@
# Release Notes
+## 3.4.1
+### Bugfixes
+- Fixed a bug where `podman machine init` could, under some circumstances, create invalid machine configurations which could not be started ([#11824](https://github.com/containers/podman/issues/11824)).
+- Fixed a bug where the `podman machine list` command would not properly populate some output fields.
+- Fixed a bug where `podman machine rm` could leave dangling sockets from the removed machine ([#11393](https://github.com/containers/podman/issues/11393)).
+- Fixed a bug where `podman run --pids-limit=-1` was not supported (it now sets the PID limit in the container to unlimited) ([#11782](https://github.com/containers/podman/issues/11782)).
+- Fixed a bug where `podman run` and `podman attach` could throw errors about a closed network connection when STDIN was closed by the client ([#11856](https://github.com/containers/podman/issues/11856)).
+- Fixed a bug where the `podman stop` command could fail when run on a container that had another `podman stop` command run on it previously.
+- Fixed a bug where the `--sync` flag to `podman ps` was nonfunctional.
+- Fixed a bug where the Windows and OS X remote clients' `podman stats` command would fail ([#11909](https://github.com/containers/podman/issues/11909)).
+- Fixed a bug where the `podman play kube` command did not properly handle environment variables whose values contained an `=` ([#11891](https://github.com/containers/podman/issues/11891)).
+- Fixed a bug where the `podman generate kube` command could generate invalid annotations when run on containers with volumes that use SELinux relabelling (`:z` or `:Z`) ([#11929](https://github.com/containers/podman/issues/11929)).
+- Fixed a bug where the `podman generate kube` command would generate YAML including some unnecessary (set to default) fields (e.g. user and group, entrypoint, default protocol for forwarded ports) ([#11914](https://github.com/containers/podman/issues/11914), [#11915](https://github.com/containers/podman/issues/11915), and [#11965](https://github.com/containers/podman/issues/11965)).
+- Fixed a bug where the `podman generate kube` command could, under some circumstances, generate YAML including an invalid `targetPort` field for forwarded ports ([#11930](https://github.com/containers/podman/issues/11930)).
+- Fixed a bug where rootless Podman's `podman info` command could, under some circumstances, not read available CGroup controllers ([#11931](https://github.com/containers/podman/issues/11931)).
+- Fixed a bug where `podman container checkpoint --export` would fail to checkpoint any container created with `--log-driver=none` ([#11974](https://github.com/containers/podman/issues/11974)).
+
+### API
+- Fixed a bug where the Compat Create endpoint for Containers could panic when no options were passed to a bind mount of tmpfs ([#11961](https://github.com/containers/podman/issues/11961)).
+
## 3.4.0
### Features
- Pods now support init containers! Init containers are containers which run before the rest of the pod starts. There are two types of init containers: "always", which always run before the pod is started, and "once", which only run the first time the pod starts and are subsequently removed. They can be added using the `podman create` command's `--init-ctr` option.
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index f3bf2c0a2..b3dfc4967 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -433,7 +433,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
pidsLimitFlagName := "pids-limit"
createFlags.Int64(
pidsLimitFlagName, pidsLimit(),
- "Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
+ "Tune container pids limit (set -1 for unlimited)",
)
_ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 09ac61f2e..50d7c446d 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -104,15 +104,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
addField(&builder, "target", m.Target)
addField(&builder, "ro", strconv.FormatBool(m.ReadOnly))
addField(&builder, "consistency", string(m.Consistency))
-
// Map any specialized mount options that intersect between *Options and cli options
switch m.Type {
case mount.TypeBind:
- addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
- addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
+ if m.BindOptions != nil {
+ addField(&builder, "bind-propagation", string(m.BindOptions.Propagation))
+ addField(&builder, "bind-nonrecursive", strconv.FormatBool(m.BindOptions.NonRecursive))
+ }
case mount.TypeTmpfs:
- addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
- addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10))
+ if m.TmpfsOptions != nil {
+ addField(&builder, "tmpfs-size", strconv.FormatInt(m.TmpfsOptions.SizeBytes, 10))
+ addField(&builder, "tmpfs-mode", strconv.FormatUint(uint64(m.TmpfsOptions.Mode), 10))
+ }
case mount.TypeVolume:
// All current VolumeOpts are handled above
// See vendor/github.com/containers/common/pkg/parse/parse.go:ValidateVolumeOpts()
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 8b27de53e..aa34f9ba5 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -224,6 +224,10 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
if c.Flags().Changed("pids-limit") {
val := c.Flag("pids-limit").Value.String()
+ // Convert -1 to 0, so that -1 maps to unlimited pids limit
+ if val == "-1" {
+ val = "0"
+ }
pidsLimit, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return vals, err
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 11e8f6870..d21feaabc 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -11,9 +11,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
- "github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/utils"
"github.com/docker/go-units"
"github.com/pkg/errors"
@@ -113,16 +111,6 @@ func checkStatOptions(cmd *cobra.Command, args []string) error {
}
func stats(cmd *cobra.Command, args []string) error {
- if rootless.IsRootless() {
- unified, err := cgroups.IsCgroup2UnifiedMode()
- if err != nil {
- return err
- }
- if !unified {
- return errors.New("stats is not supported in rootless mode without cgroups v2")
- }
- }
-
// Convert to the entities options. We should not leak CLI-only
// options into the backend and separate concerns.
opts := entities.ContainerStatsOptions{
diff --git a/cmd/podman/diff/diff.go b/cmd/podman/diff/diff.go
index 81bbb6c43..fba4ea540 100644
--- a/cmd/podman/diff/diff.go
+++ b/cmd/podman/diff/diff.go
@@ -8,7 +8,7 @@ import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/docker/docker/pkg/archive"
+ "github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
diff --git a/contrib/cirrus/pr-should-include-tests b/contrib/cirrus/pr-should-include-tests
index 09ab002cf..4b6329311 100755
--- a/contrib/cirrus/pr-should-include-tests
+++ b/contrib/cirrus/pr-should-include-tests
@@ -8,7 +8,10 @@ if [[ "${CIRRUS_CHANGE_TITLE}" =~ CI:DOCS ]]; then
exit 0
fi
-# So are PRs where 'NO TESTS NEEDED' appears in the Github message
+# So are PRs where 'NO NEW TESTS NEEDED' appears in the Github message
+if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.NEW.TESTS.NEEDED ]]; then
+ exit 0
+fi
if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.TESTS.NEEDED ]]; then
exit 0
fi
@@ -49,8 +52,11 @@ if [[ -z "$filtered_changes" ]]; then
exit 0
fi
-# One last chance: perhaps the developer included the magic '[NO TESTS NEEDED]'
+# One last chance: perhaps the developer included the magic '[NO (NEW) TESTS NEEDED]'
# string in an amended commit.
+if git log --format=%B ${base}..${head} | fgrep '[NO NEW TESTS NEEDED]'; then
+ exit 0
+fi
if git log --format=%B ${base}..${head} | fgrep '[NO TESTS NEEDED]'; then
exit 0
fi
@@ -67,7 +73,7 @@ tests, possibly just adding a small step to a similar existing test.
Every second counts in CI.
If your commit really, truly does not need tests, you can proceed
-by adding '[NO TESTS NEEDED]' to the body of your commit message.
+by adding '[NO NEW TESTS NEEDED]' to the body of your commit message.
Please think carefully before doing so.
EOF
diff --git a/contrib/cirrus/pr-should-include-tests.t b/contrib/cirrus/pr-should-include-tests.t
index 965a3b574..e77608fa4 100755
--- a/contrib/cirrus/pr-should-include-tests.t
+++ b/contrib/cirrus/pr-should-include-tests.t
@@ -36,9 +36,9 @@ tests="
0 a47515008 ecedda63a PR 8816, unit tests only
0 caa84cd35 e55320efd PR 8565, hack/podman-socat only
0 c342583da 12f835d12 PR 8523, version.go + podman.spec.in
-0 c342583da db1d2ff11 version bump to v2.2.0
0 8f75ed958 7b3ad6d89 PR 8835, only a README.md change
0 b6db60e58 f06dd45e0 PR 9420, a test rename
+0 c6a896b0c 4ea5d6971 PR 11833, includes magic string
"
# The script we're testing
diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile
index baad49e08..75de947ea 100644
--- a/contrib/podmanimage/upstream/Dockerfile
+++ b/contrib/podmanimage/upstream/Dockerfile
@@ -40,7 +40,8 @@ RUN yum -y update; rpm --restore shadow-utils 2>/dev/null; yum -y install --exc
crun \
fuse-overlayfs \
fuse3 \
- containers-common; \
+ containers-common \
+ podman-plugins; \
mkdir /root/podman; \
git clone https://github.com/containers/podman /root/podman/src/github.com/containers/podman; \
cd /root/podman/src/github.com/containers/podman; \
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 0344c1776..683797cd0 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -36,7 +36,7 @@ Epoch: 99
%else
Epoch: 0
%endif
-Version: 3.4.1
+Version: 3.4.2
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 00601e778..40439dacb 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -721,7 +721,7 @@ Default is to create a private PID namespace for the container
#### **--pids-limit**=*limit*
-Tune the container's pids limit. Set `0` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups).
+Tune the container's pids limit. Set `-1` to have unlimited pids for the container. (default "4096" on systems that support PIDS cgroups).
#### **--platform**=*OS/ARCH*
diff --git a/docs/source/markdown/podman-manifest.1.md b/docs/source/markdown/podman-manifest.1.md
index 6b82cc1ad..964f89afe 100644
--- a/docs/source/markdown/podman-manifest.1.md
+++ b/docs/source/markdown/podman-manifest.1.md
@@ -24,5 +24,49 @@ The `podman manifest` command provides subcommands which can be used to:
| remove | [podman-manifest-remove(1)](podman-manifest-remove.1.md) | Remove an image from a manifest list or image index. |
| rm | [podman-manifest-rme(1)](podman-manifest-rm.1.md) | Remove manifest list or image index from local storage. |
+## EXAMPLES
+
+### Building a multi-arch manifest list from a Containerfile
+
+Assuming the `Containerfile` uses `RUN` instructions, the host needs
+a way to execute non-native binaries. Configuring this is beyond
+the scope of this example. Building a multi-arch manifest list
+`shazam` in parallel across 4-threads can be done like this:
+
+ $ platarch=linux/amd64,linux/ppc64le,linux/arm64,linux/s390x
+ $ podman build --jobs=4 --platform=$platarch --manifest shazam .
+
+**Note:** The `--jobs` argument is optional, and the `-t` or `--tag`
+option should *not* be used.
+
+### Assembling a multi-arch manifest from separately built images
+
+Assuming `example.com/example/shazam:$arch` images are built separately
+on other hosts and pushed to the `example.com` registry. They may
+be combined into a manifest list, and pushed using a simple loop:
+
+ $ REPO=example.com/example/shazam
+ $ podman manifest create $REPO:latest
+ $ for IMGTAG in amd64 s390x ppc64le arm64; do \
+ podman manifest add $REPO:latest docker://$REPO:IMGTAG; \
+ done
+ $ podman manifest push --all $REPO:latest
+
+**Note:** The `add` instruction argument order is `<manifest>` then `<image>`.
+Also, the `--all` push option is required to ensure all contents are
+pushed, not just the native platform/arch.
+
+### Removing and tagging a manifest list before pushing
+
+Special care is needed when removing and pushing manifest lists, as opposed
+to the contents. You almost always want to use the `manifest rm` and
+`manifest push --all` subcommands. For example, a rename and push could
+be performed like this:
+
+ $ podman tag localhost/shazam example.com/example/shazam
+ $ podman manifest rm localhost/shazam
+ $ podman manifest push --all example.com/example/shazam
+
+
## SEE ALSO
podman(1), podman-manifest-add(1), podman-manifest-annotate(1), podman-manifest-create(1), podman-manifest-inspect(1), podman-manifest-push(1), podman-manifest-remove(1)
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index fccb51cd8..c538935fd 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -743,7 +743,7 @@ The default is to create a private PID namespace for the container.
#### **--pids-limit**=*limit*
-Tune the container's pids limit. Set to **0** to have unlimited pids for the container. The default is **4096** on systems that support "pids" cgroup controller.
+Tune the container's pids limit. Set to **-1** to have unlimited pids for the container. The default is **4096** on systems that support "pids" cgroup controller.
#### **--platform**=*OS/ARCH*
diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 8abba3763..864ff34bc 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -82,7 +82,7 @@ Remote connections use local containers.conf for default.
#### **--log-level**=*level*
-Log messages above specified level: debug, info, warn, error (default), fatal or panic (default: "error")
+Log messages at and above specified level: debug, info, warn, error, fatal or panic (default: "warn")
#### **--namespace**=*namespace*
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 637f5b686..c6f459fbd 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -184,7 +184,7 @@ func (c *Container) StopWithTimeout(timeout uint) error {
return define.ErrCtrStopped
}
- if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) {
+ if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStateStopping) {
return errors.Wrapf(define.ErrCtrStateInvalid, "can only stop created or running containers. %s is in state %s", c.ID(), c.state.State.String())
}
@@ -686,7 +686,7 @@ func (c *Container) Sync() error {
// If runtime knows about the container, update its status in runtime
// And then save back to disk
- if c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopped) {
+ if c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopped, define.ContainerStateStopping) {
oldState := c.state.State
if err := c.ociRuntime.UpdateContainerStatus(c); err != nil {
return err
diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go
index 7d4dd0d46..954d54a1d 100644
--- a/libpod/container_copy_linux.go
+++ b/libpod/container_copy_linux.go
@@ -15,8 +15,8 @@ import (
"github.com/containers/buildah/util"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/idtools"
- "github.com/docker/docker/pkg/archive"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 89287efc9..310110679 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -974,12 +974,15 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
includeFiles := []string{
"artifacts",
- "ctr.log",
metadata.ConfigDumpFile,
metadata.SpecDumpFile,
metadata.NetworkStatusFile,
}
+ if c.LogDriver() == define.KubernetesLogging ||
+ c.LogDriver() == define.JSONLogging {
+ includeFiles = append(includeFiles, "ctr.log")
+ }
if options.PreCheckPoint {
includeFiles = append(includeFiles, preCheckpointDir)
} else {
diff --git a/libpod/kube.go b/libpod/kube.go
index cb97eb5ab..f5291ce60 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -25,6 +25,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
)
// GenerateForKube takes a slice of libpod containers and generates
@@ -196,10 +197,11 @@ func containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.Servic
for _, cp := range containerPorts {
nodePort := 30000 + rand.Intn(32767-30000+1)
servicePort := v1.ServicePort{
- Protocol: cp.Protocol,
- Port: cp.ContainerPort,
- NodePort: int32(nodePort),
- Name: strconv.Itoa(int(cp.ContainerPort)),
+ Protocol: cp.Protocol,
+ Port: cp.ContainerPort,
+ NodePort: int32(nodePort),
+ Name: strconv.Itoa(int(cp.ContainerPort)),
+ TargetPort: intstr.Parse(strconv.Itoa(int(cp.ContainerPort))),
}
sps = append(sps, servicePort)
}
@@ -246,7 +248,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
return nil, err
}
for k, v := range annotations {
- podAnnotations[define.BindMountPrefix+k] = v
+ podAnnotations[define.BindMountPrefix+k] = strings.TrimSpace(v)
}
// Since port bindings for the pod are handled by the
// infra container, wipe them here.
@@ -366,7 +368,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
return nil, err
}
for k, v := range annotations {
- kubeAnnotations[define.BindMountPrefix+k] = v
+ kubeAnnotations[define.BindMountPrefix+k] = strings.TrimSpace(v)
}
if isInit {
kubeInitCtrs = append(kubeInitCtrs, kubeCtr)
@@ -481,10 +483,16 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
if err != nil {
return kubeContainer, kubeVolumes, nil, annotations, err
}
- if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) {
+ // If the user doesn't set a command/entrypoint when creating the container with podman and
+ // is using the image command or entrypoint from the image, don't add it to the generated kube yaml
+ if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) || reflect.DeepEqual(imgData.Config.Entrypoint, kubeContainer.Command) {
kubeContainer.Command = nil
}
+ if imgData.User == c.User() {
+ kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil
+ }
+
kubeContainer.WorkingDir = c.WorkingDir()
kubeContainer.Ports = ports
// This should not be applicable
@@ -572,7 +580,8 @@ func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.C
var protocol v1.Protocol
switch strings.ToUpper(p.Protocol) {
case "TCP":
- protocol = v1.ProtocolTCP
+ // do nothing as it is the default protocol in k8s, there is no need to explicitly
+ // add it to the generated yaml
case "UDP":
protocol = v1.ProtocolUDP
default:
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go
index de435b58a..702628aa8 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_attach_linux.go
@@ -84,7 +84,7 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
if attachRdy != nil {
attachRdy <- true
}
- return readStdio(streams, receiveStdoutError, stdinDone)
+ return readStdio(conn, streams, receiveStdoutError, stdinDone)
}
// Attach to the given container's exec session
@@ -165,7 +165,7 @@ func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, se
return err
}
- return readStdio(streams, receiveStdoutError, stdinDone)
+ return readStdio(conn, streams, receiveStdoutError, stdinDone)
}
func processDetachKeys(keys string) ([]byte, error) {
@@ -208,11 +208,6 @@ func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detac
var err error
if streams.AttachInput {
_, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys)
- if err == nil {
- if connErr := conn.CloseWrite(); connErr != nil {
- logrus.Errorf("unable to close conn: %q", connErr)
- }
- }
}
stdinDone <- err
}()
@@ -265,7 +260,7 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO
return err
}
-func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error {
+func readStdio(conn *net.UnixConn, streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error {
var err error
select {
case err = <-receiveStdoutError:
@@ -274,6 +269,12 @@ func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan
if err == define.ErrDetach {
return err
}
+ if err == nil {
+ // copy stdin is done, close it
+ if connErr := conn.CloseWrite(); connErr != nil {
+ logrus.Errorf("Unable to close conn: %v", connErr)
+ }
+ }
if streams.AttachOutput || streams.AttachError {
return <-receiveStdoutError
}
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index 5a7677b04..553c91833 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -609,9 +609,6 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
_, err := utils.CopyDetachable(conn, httpBuf, detachKeys)
logrus.Debugf("STDIN copy completed")
stdinChan <- err
- if connErr := conn.CloseWrite(); connErr != nil {
- logrus.Errorf("Unable to close conn: %v", connErr)
- }
}()
}
@@ -654,6 +651,10 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
if err != nil {
return err
}
+ // copy stdin is done, close it
+ if connErr := conn.CloseWrite(); connErr != nil {
+ logrus.Errorf("Unable to close conn: %v", connErr)
+ }
case <-cancel:
return nil
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index c2b472f76..ea0ef842d 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -351,6 +351,12 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error {
return ctr.handleExitFile(exitFile, fi)
}
+ // Handle ContainerStateStopping - keep it unless the container
+ // transitioned to no longer running.
+ if oldState == define.ContainerStateStopping && (ctr.state.State == define.ContainerStatePaused || ctr.state.State == define.ContainerStateRunning) {
+ ctr.state.State = define.ContainerStateStopping
+ }
+
return nil
}
@@ -699,6 +705,10 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
if err != nil {
return err
}
+ // copy stdin is done, close it
+ if connErr := conn.CloseWrite(); connErr != nil {
+ logrus.Errorf("Unable to close conn: %v", connErr)
+ }
case <-cancel:
return nil
}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 6efbcb57b..725d06648 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -157,24 +157,24 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
}
stdoutChan := make(chan error)
- stdinChan := make(chan error)
+ stdinChan := make(chan error, 1) //stdin channel should not block
if isSet.stdin {
go func() {
logrus.Debugf("Copying STDIN to socket")
_, err := utils.CopyDetachable(socket, stdin, detachKeysInBytes)
-
if err != nil && err != define.ErrDetach {
logrus.Error("failed to write input to service: " + err.Error())
}
- stdinChan <- err
-
- if closeWrite, ok := socket.(CloseWriter); ok {
- if err := closeWrite.CloseWrite(); err != nil {
- logrus.Warnf("Failed to close STDIN for writing: %v", err)
+ if err == nil {
+ if closeWrite, ok := socket.(CloseWriter); ok {
+ if err := closeWrite.CloseWrite(); err != nil {
+ logrus.Warnf("Failed to close STDIN for writing: %v", err)
+ }
}
}
+ stdinChan <- err
}()
}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index 4d667d90a..4c3c83837 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -16,6 +16,7 @@ import (
"strconv"
"strings"
+ "github.com/containers/buildah/define"
"github.com/containers/podman/v3/pkg/auth"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -39,6 +40,10 @@ var (
// Build creates an image using a containerfile reference
func Build(ctx context.Context, containerFiles []string, options entities.BuildOptions) (*entities.BuildReport, error) {
+ if options.CommonBuildOpts == nil {
+ options.CommonBuildOpts = new(define.CommonBuildOptions)
+ }
+
params := url.Values{}
if caps := options.AddCapabilities; len(caps) > 0 {
diff --git a/pkg/bindings/test/fixture/Containerfile b/pkg/bindings/test/fixture/Containerfile
new file mode 100644
index 000000000..3a1031f32
--- /dev/null
+++ b/pkg/bindings/test/fixture/Containerfile
@@ -0,0 +1 @@
+From quay.io/libpod/alpine_nginx
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index ff8f72c85..aa8ff0537 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,9 +9,11 @@ import (
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/bindings/containers"
"github.com/containers/podman/v3/pkg/bindings/images"
+ "github.com/containers/podman/v3/pkg/domain/entities"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
- "github.com/onsi/gomega/gexec"
+ . "github.com/onsi/gomega/gexec"
+ . "github.com/onsi/gomega/gstruct"
)
var _ = Describe("Podman images", func() {
@@ -20,7 +22,7 @@ var _ = Describe("Podman images", func() {
// err error
// podmanTest *PodmanTestIntegration
bt *bindingTest
- s *gexec.Session
+ s *Session
err error
)
@@ -37,7 +39,7 @@ var _ = Describe("Podman images", func() {
s = bt.startAPIService()
time.Sleep(1 * time.Second)
err := bt.NewConnection()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
@@ -57,19 +59,19 @@ var _ = Describe("Podman images", func() {
// Inspect by short name
data, err := images.GetImage(bt.conn, alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect with full ID
_, err = images.GetImage(bt.conn, data.ID, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect with partial ID
_, err = images.GetImage(bt.conn, data.ID[0:12], nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Inspect by long name
_, err = images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// TODO it looks like the images API always returns size regardless
// of bool or not. What should we do ?
// Expect(data.Size).To(BeZero())
@@ -77,7 +79,7 @@ var _ = Describe("Podman images", func() {
options := new(images.GetOptions).WithSize(true)
// Enabling the size parameter should result in size being populated
data, err = images.GetImage(bt.conn, alpine.name, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(data.Size).To(BeNumerically(">", 0))
})
@@ -90,7 +92,7 @@ var _ = Describe("Podman images", func() {
// Remove an image by name, validate image is removed and error is nil
inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
response, errs = images.Remove(bt.conn, []string{busybox.shortName}, nil)
Expect(len(errs)).To(BeZero())
@@ -101,10 +103,10 @@ var _ = Describe("Podman images", func() {
// Start a container with alpine image
var top string = "top"
_, err = bt.RunTopContainer(&top, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// we should now have a container called "top" running
containerResponse, err := containers.Inspect(bt.conn, "top", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(containerResponse.Name).To(Equal("top"))
// try to remove the image "alpine". This should fail since we are not force
@@ -115,7 +117,7 @@ var _ = Describe("Podman images", func() {
// Removing the image "alpine" where force = true
options := new(images.RemoveOptions).WithForce(true)
response, errs = images.Remove(bt.conn, []string{alpine.shortName}, options)
- Expect(errs).To(BeNil())
+ Expect(errs).To(Or(HaveLen(0), BeNil()))
// To be extra sure, check if the previously created container
// is gone as well.
_, err = containers.Inspect(bt.conn, "top", nil)
@@ -141,11 +143,11 @@ var _ = Describe("Podman images", func() {
// Validates if the image is tagged successfully.
err = images.Tag(bt.conn, alpine.shortName, "demo", alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Validates if name updates when the image is retagged.
_, err := images.GetImage(bt.conn, "alpine:demo", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
})
@@ -154,7 +156,7 @@ var _ = Describe("Podman images", func() {
// Array to hold the list of images returned
imageSummary, err := images.List(bt.conn, nil)
// There Should be no errors in the response.
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// Since in the begin context two images are created the
// list context should have only 2 images
Expect(len(imageSummary)).To(Equal(2))
@@ -163,23 +165,23 @@ var _ = Describe("Podman images", func() {
// And the count should be three now.
bt.Pull("testimage:20200929")
imageSummary, err = images.List(bt.conn, nil)
- Expect(err).To(BeNil())
- Expect(len(imageSummary)).To(Equal(3))
+ Expect(err).ToNot(HaveOccurred())
+ Expect(len(imageSummary)).To(BeNumerically(">=", 2))
// Validate the image names.
var names []string
for _, i := range imageSummary {
names = append(names, i.RepoTags...)
}
- Expect(StringInSlice(alpine.name, names)).To(BeTrue())
- Expect(StringInSlice(busybox.name, names)).To(BeTrue())
+ Expect(names).To(ContainElement(alpine.name))
+ Expect(names).To(ContainElement(busybox.name))
// List images with a filter
filters := make(map[string][]string)
filters["reference"] = []string{alpine.name}
options := new(images.ListOptions).WithFilters(filters).WithAll(false)
filteredImages, err := images.List(bt.conn, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(filteredImages)).To(BeNumerically("==", 1))
// List images with a bad filter
@@ -194,17 +196,17 @@ var _ = Describe("Podman images", func() {
It("Image Exists", func() {
// exists on bogus image should be false, with no error
exists, err := images.Exists(bt.conn, "foobar", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
// exists with shortname should be true
exists, err = images.Exists(bt.conn, alpine.shortName, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
// exists with fqname should be true
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
})
@@ -213,37 +215,37 @@ var _ = Describe("Podman images", func() {
_, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
defer f.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
names, err := images.Load(bt.conn, f)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(names.Names[0]).To(Equal(alpine.name))
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
// load with a repo name
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
names, err = images.Load(bt.conn, f)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(names.Names[0]).To(Equal(alpine.name))
// load with a bad repo name should trigger a 500
f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, errs = images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
})
@@ -252,11 +254,11 @@ var _ = Describe("Podman images", func() {
exportPath := filepath.Join(bt.tempDirPath, alpine.tarballName)
w, err := os.Create(filepath.Join(bt.tempDirPath, alpine.tarballName))
defer w.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
err = images.Export(bt.conn, []string{alpine.name}, w, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
_, err = os.Stat(exportPath)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
// TODO how do we verify that a format change worked?
})
@@ -266,21 +268,21 @@ var _ = Describe("Podman images", func() {
_, errs := images.Remove(bt.conn, []string{alpine.name}, nil)
Expect(len(errs)).To(BeZero())
exists, err := images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
f, err := os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
defer f.Close()
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
changes := []string{"CMD /bin/foobar"}
testMessage := "test_import"
options := new(images.ImportOptions).WithMessage(testMessage).WithChanges(changes).WithReference(alpine.name)
_, err = images.Import(bt.conn, f, options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
exists, err = images.Exists(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeTrue())
data, err := images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(data.Comment).To(Equal(testMessage))
})
@@ -294,9 +296,9 @@ var _ = Describe("Podman images", func() {
var foundID bool
data, err := images.GetImage(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
history, err := images.History(bt.conn, alpine.name, nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
for _, i := range history {
if i.ID == data.ID {
foundID = true
@@ -308,7 +310,7 @@ var _ = Describe("Podman images", func() {
It("Search for an image", func() {
reports, err := images.Search(bt.conn, "alpine", nil)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(reports)).To(BeNumerically(">", 1))
var foundAlpine bool
for _, i := range reports {
@@ -322,7 +324,7 @@ var _ = Describe("Podman images", func() {
// Search for alpine with a limit of 10
options := new(images.SearchOptions).WithLimit(10)
reports, err = images.Search(bt.conn, "docker.io/alpine", options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
Expect(len(reports)).To(BeNumerically("<=", 10))
filters := make(map[string][]string)
@@ -330,7 +332,7 @@ var _ = Describe("Podman images", func() {
// Search for alpine with stars greater than 100
options = new(images.SearchOptions).WithFilters(filters)
reports, err = images.Search(bt.conn, "docker.io/alpine", options)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
for _, i := range reports {
Expect(i.Stars).To(BeNumerically(">=", 100))
}
@@ -367,4 +369,12 @@ var _ = Describe("Podman images", func() {
_, err = images.Pull(bt.conn, "bogus-transport:bogus.com/image:reference", nil)
Expect(err).To(HaveOccurred())
})
+
+ It("Build no options", func() {
+ results, err := images.Build(bt.conn, []string{"fixture/Containerfile"}, entities.BuildOptions{})
+ Expect(err).ToNot(HaveOccurred())
+ Expect(*results).To(MatchFields(IgnoreMissing, Fields{
+ "ID": Not(BeEmpty()),
+ }))
+ })
})
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 4bb8de69b..f1ef538e4 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -129,8 +129,8 @@ func init() {
func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]controller, error) {
if cgroup2 {
controllers := []controller{}
- subtreeControl := cgroupRoot + "/cgroup.subtree_control"
- // rootless cgroupv2: check available controllers for current user ,systemd or servicescope will inherit
+ controllersFile := cgroupRoot + "/cgroup.controllers"
+ // rootless cgroupv2: check available controllers for current user, systemd or servicescope will inherit
if rootless.IsRootless() {
userSlice, err := getCgroupPathForCurrentProcess()
if err != nil {
@@ -138,13 +138,13 @@ func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool)
}
//userSlice already contains '/' so not adding here
basePath := cgroupRoot + userSlice
- subtreeControl = fmt.Sprintf("%s/cgroup.subtree_control", basePath)
+ controllersFile = fmt.Sprintf("%s/cgroup.controllers", basePath)
}
- subtreeControlBytes, err := ioutil.ReadFile(subtreeControl)
+ controllersFileBytes, err := ioutil.ReadFile(controllersFile)
if err != nil {
- return nil, errors.Wrapf(err, "failed while reading controllers for cgroup v2 from %q", subtreeControl)
+ return nil, errors.Wrapf(err, "failed while reading controllers for cgroup v2 from %q", controllersFile)
}
- for _, controllerName := range strings.Fields(string(subtreeControlBytes)) {
+ for _, controllerName := range strings.Fields(string(controllersFileBytes)) {
c := controller{
name: controllerName,
symlink: false,
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 774362d03..d1e430f3b 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1316,6 +1316,15 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
if options.Interval < 1 {
return nil, errors.New("Invalid interval, must be a positive number greater zero")
}
+ if rootless.IsRootless() {
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return nil, err
+ }
+ if !unified {
+ return nil, errors.New("stats is not supported in rootless mode without cgroups v2")
+ }
+ }
statsChan = make(chan entities.ContainerStatsReport, 1)
containerFunc := ic.Libpod.GetRunningContainers
diff --git a/pkg/hooks/docs/oci-hooks.5.md b/pkg/hooks/docs/oci-hooks.5.md
index d6b866231..9a1a35682 100644
--- a/pkg/hooks/docs/oci-hooks.5.md
+++ b/pkg/hooks/docs/oci-hooks.5.md
@@ -1,4 +1,4 @@
-% oci-hooks(5) OCI Hooks Configuration
+% oci-hooks 5 OCI Hooks Configuration
% W. Trevor King
% MAY 2018
diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go
index f79ac6ec4..3c8422a30 100644
--- a/pkg/machine/pull.go
+++ b/pkg/machine/pull.go
@@ -15,7 +15,7 @@ import (
"time"
"github.com/containers/image/v5/pkg/compression"
- "github.com/docker/docker/pkg/archive"
+ "github.com/containers/storage/pkg/archive"
"github.com/sirupsen/logrus"
"github.com/vbauerster/mpb/v6"
"github.com/vbauerster/mpb/v6/decor"
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index d0f48da5f..03197fef1 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -460,6 +460,22 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
for _, msg := range files {
confirmationMessage += msg + "\n"
}
+
+ // Get path to socket and pidFile before we do any cleanups
+ qemuSocketFile, pidFile, errSocketFile := v.getSocketandPid()
+ //silently try to delete socket and pid file
+ //remove socket and pid file if any: warn at low priority if things fail
+ if errSocketFile == nil {
+ // Remove the pidfile
+ if err := os.Remove(pidFile); err != nil && !errors.Is(err, os.ErrNotExist) {
+ logrus.Debugf("Error while removing pidfile: %v", err)
+ }
+ // Remove socket
+ if err := os.Remove(qemuSocketFile); err != nil && !errors.Is(err, os.ErrNotExist) {
+ logrus.Debugf("Error while removing podman-machine-socket: %v", err)
+ }
+ }
+
confirmationMessage += "\n"
return confirmationMessage, func() error {
for _, f := range files {
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index e65400555..21ce818cb 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -127,6 +127,12 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
)
batchErr := ctr.Batch(func(c *libpod.Container) error {
+ if opts.Sync {
+ if err := c.Sync(); err != nil {
+ return errors.Wrapf(err, "unable to update container state from OCI runtime")
+ }
+ }
+
conConfig = c.Config()
conState, err = c.State()
if err != nil {
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index 27a1e5a72..7072a5821 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -254,7 +254,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
// Environment Variables
envs := map[string]string{}
for _, env := range imageData.Config.Env {
- keyval := strings.Split(env, "=")
+ keyval := strings.SplitN(env, "=", 2)
envs[keyval[0]] = keyval[1]
}
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
index 50efe7fa3..b0d84825e 100644
--- a/pkg/specgen/generate/validate.go
+++ b/pkg/specgen/generate/validate.go
@@ -72,10 +72,9 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error
// Pids checks
if s.ResourceLimits.Pids != nil {
- pids := s.ResourceLimits.Pids
// TODO: Should this be 0, or checking that ResourceLimits.Pids
// is set at all?
- if pids.Limit > 0 && !sysInfo.PidsLimit {
+ if s.ResourceLimits.Pids.Limit >= 0 && !sysInfo.PidsLimit {
warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
s.ResourceLimits.Pids = nil
}
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index afff68c22..748a0750f 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -379,3 +379,21 @@ t GET containers/$cid/json 200 \
.HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.*
t DELETE containers/$cid?v=true 204
+
+# compat api: tmpfs without mount options
+payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch"}]}'
+t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
+cid=$(jq -r '.Id' <<<"$output")
+t GET containers/$cid/json 200 \
+ .HostConfig.Tmpfs['"/mnt/scratch"']~.*tmpcopyup.* \
+
+t DELETE containers/$cid?v=true 204
+
+# compat api: bind mount without mount options
+payload='{"Mounts":[{"Type":"bind","Source":"/tmp","Target":"/mnt"}]}'
+t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
+cid=$(jq -r '.Id' <<<"$output")
+t GET containers/$cid/json 200 \
+ .HostConfig.Binds[0]~/tmp:/mnt:.* \
+
+t DELETE containers/$cid?v=true 204
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 403d739f0..0d89772f6 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -6,10 +6,12 @@ import (
"os"
"os/exec"
"strings"
+ "time"
"github.com/containers/podman/v3/pkg/checkpoint/crutils"
"github.com/containers/podman/v3/pkg/criu"
. "github.com/containers/podman/v3/test/utils"
+ "github.com/containers/podman/v3/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -247,16 +249,19 @@ var _ = Describe("Podman checkpoint", func() {
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
+ cid := session.OutputToString()
+ if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) {
+ Fail("Container failed to get ready")
+ }
IP := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
IP.WaitWithDefaultTimeout()
Expect(IP).Should(Exit(0))
// Open a network connection to the redis server
- conn, err := net.Dial("tcp", IP.OutputToString()+":6379")
- if err != nil {
- os.Exit(1)
- }
+ conn, err := net.DialTimeout("tcp4", IP.OutputToString()+":6379", time.Duration(3)*time.Second)
+ Expect(err).To(BeNil())
+
// This should fail as the container has established TCP connections
result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
result.WaitWithDefaultTimeout()
@@ -933,18 +938,23 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore container with different port mappings", func() {
- localRunString := getRunString([]string{"-p", "1234:6379", "--rm", redis})
+ randomPort, err := utils.GetRandomPort()
+ Expect(err).ShouldNot(HaveOccurred())
+ localRunString := getRunString([]string{"-p", fmt.Sprintf("%d:6379", randomPort), "--rm", redis})
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
cid := session.OutputToString()
fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
- // Open a network connection to the redis server via initial port mapping
- conn, err := net.Dial("tcp", "localhost:1234")
- if err != nil {
- os.Exit(1)
+ if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) {
+ Fail("Container failed to get ready")
}
+
+ fmt.Fprintf(os.Stderr, "Trying to connect to redis server at localhost:%d", randomPort)
+ // Open a network connection to the redis server via initial port mapping
+ conn, err := net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second)
+ Expect(err).ShouldNot(HaveOccurred())
conn.Close()
// Checkpoint the container
@@ -958,7 +968,9 @@ var _ = Describe("Podman checkpoint", func() {
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
// Restore container with different port mapping
- result = podmanTest.Podman([]string{"container", "restore", "-p", "1235:6379", "-i", fileName})
+ newRandomPort, err := utils.GetRandomPort()
+ Expect(err).ShouldNot(HaveOccurred())
+ result = podmanTest.Podman([]string{"container", "restore", "-p", fmt.Sprintf("%d:6379", newRandomPort), "-i", fileName})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
@@ -967,13 +979,12 @@ var _ = Describe("Podman checkpoint", func() {
// Open a network connection to the redis server via initial port mapping
// This should fail
- conn, err = net.Dial("tcp", "localhost:1234")
+ conn, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second)
Expect(err.Error()).To(ContainSubstring("connection refused"))
// Open a network connection to the redis server via new port mapping
- conn, err = net.Dial("tcp", "localhost:1235")
- if err != nil {
- os.Exit(1)
- }
+ fmt.Fprintf(os.Stderr, "Trying to reconnect to redis server at localhost:%d", newRandomPort)
+ conn, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", newRandomPort), time.Duration(3)*time.Second)
+ Expect(err).ShouldNot(HaveOccurred())
conn.Close()
result = podmanTest.Podman([]string{"rm", "-fa"})
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index cb987e139..07515fe7b 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "strings"
"github.com/containers/podman/v3/libpod/define"
@@ -119,20 +120,28 @@ var _ = Describe("Podman generate kube", func() {
Expect(kube.OutputToString()).To(ContainSubstring("type: foo_bar_t"))
})
- It("podman generate service kube on container", func() {
- session := podmanTest.RunTopContainer("top")
+ It("podman generate service kube on container - targetPort should match port name", func() {
+ session := podmanTest.Podman([]string{"create", "--name", "test-ctr", "-p", "3890:3890", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- kube := podmanTest.Podman([]string{"generate", "kube", "-s", "top"})
+ kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-ctr"})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
- // TODO - test generated YAML - service produces multiple
- // structs.
- // pod := new(v1.Pod)
- // err := yaml.Unmarshal([]byte(kube.OutputToString()), pod)
- // Expect(err).To(BeNil())
+ // Separate out the Service and Pod yaml
+ arr := strings.Split(string(kube.Out.Contents()), "---")
+ Expect(len(arr)).To(Equal(2))
+
+ svc := new(v1.Service)
+ err := yaml.Unmarshal([]byte(arr[0]), svc)
+ Expect(err).To(BeNil())
+ Expect(len(svc.Spec.Ports)).To(Equal(1))
+ Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(3890))
+
+ pod := new(v1.Pod)
+ err = yaml.Unmarshal([]byte(arr[1]), pod)
+ Expect(err).To(BeNil())
})
It("podman generate kube on pod", func() {
@@ -315,21 +324,28 @@ var _ = Describe("Podman generate kube", func() {
})
It("podman generate service kube on pod", func() {
- _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {"toppod"}})
- Expect(rc).To(Equal(0))
-
- session := podmanTest.RunTopContainerInPod("topcontainer", "toppod")
+ session := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "4000:4000/udp", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- kube := podmanTest.Podman([]string{"generate", "kube", "-s", "toppod"})
+ kube := podmanTest.Podman([]string{"generate", "kube", "-s", "test-pod"})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
- // TODO: How do we test unmarshal with a service? We have two
- // structs that need to be unmarshalled...
- // _, err := yaml.Marshal(kube.OutputToString())
- // Expect(err).To(BeNil())
+ // Separate out the Service and Pod yaml
+ arr := strings.Split(string(kube.Out.Contents()), "---")
+ Expect(len(arr)).To(Equal(2))
+
+ svc := new(v1.Service)
+ err := yaml.Unmarshal([]byte(arr[0]), svc)
+ Expect(err).To(BeNil())
+ Expect(len(svc.Spec.Ports)).To(Equal(1))
+ Expect(svc.Spec.Ports[0].TargetPort.IntValue()).To(Equal(4000))
+ Expect(svc.Spec.Ports[0].Protocol).To(Equal(v1.ProtocolUDP))
+
+ pod := new(v1.Pod)
+ err = yaml.Unmarshal([]byte(arr[1]), pod)
+ Expect(err).To(BeNil())
})
It("podman generate kube on pod with restartPolicy", func() {
@@ -451,6 +467,10 @@ var _ = Describe("Podman generate kube", func() {
foundOtherPort := 0
for _, ctr := range pod.Spec.Containers {
for _, port := range ctr.Ports {
+ // Since we are using tcp here, the generated kube yaml shouldn't
+ // have anything for protocol under the ports as tcp is the default
+ // for k8s
+ Expect(port.Protocol).To(BeEmpty())
if port.HostPort == 4000 {
foundPort4000 = foundPort4000 + 1
} else if port.HostPort == 5000 {
@@ -463,6 +483,24 @@ var _ = Describe("Podman generate kube", func() {
Expect(foundPort4000).To(Equal(1))
Expect(foundPort5000).To(Equal(1))
Expect(foundOtherPort).To(Equal(0))
+
+ // Create container with UDP port and check the generated kube yaml
+ ctrWithUDP := podmanTest.Podman([]string{"create", "--pod", "new:test-pod", "-p", "6666:66/udp", ALPINE, "top"})
+ ctrWithUDP.WaitWithDefaultTimeout()
+ Expect(ctrWithUDP).Should(Exit(0))
+
+ kube = podmanTest.Podman([]string{"generate", "kube", "test-pod"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ pod = new(v1.Pod)
+ err = yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ containers := pod.Spec.Containers
+ Expect(len(containers)).To(Equal(1))
+ Expect(len(containers[0].Ports)).To(Equal(1))
+ Expect(containers[0].Ports[0].Protocol).To(Equal(v1.ProtocolUDP))
})
It("podman generate and reimport kube on pod", func() {
@@ -803,7 +841,7 @@ var _ = Describe("Podman generate kube", func() {
Expect(containers[0].Args).To(Equal([]string{"10s"}))
})
- It("podman generate kube - no command", func() {
+ It("podman generate kube - use command from image unless explicitly set in the podman command", func() {
session := podmanTest.Podman([]string{"create", "--name", "test", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -812,8 +850,8 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
- // Now make sure that the container's command is not set to the
- // entrypoint and it's arguments to "10s".
+ // Now make sure that the container's command in the kube yaml is not set to the
+ // image command.
pod := new(v1.Pod)
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
@@ -831,8 +869,8 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
- // Now make sure that the container's command is not set to the
- // entrypoint and it's arguments to "10s".
+ // Now make sure that the container's command in the kube yaml is set to the
+ // command passed via the cli to podman create.
pod = new(v1.Pod)
err = yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
@@ -842,10 +880,10 @@ var _ = Describe("Podman generate kube", func() {
Expect(containers[0].Command).To(Equal(cmd))
})
- It("podman generate kube - use entrypoint from image", func() {
+ It("podman generate kube - use entrypoint from image unless --entrypoint is set", func() {
// Build an image with an entrypoint.
containerfile := `FROM quay.io/libpod/alpine:latest
-ENTRYPOINT /bin/sleep`
+ENTRYPOINT ["sleep"]`
targetPath, err := CreateTempDirInTempDir()
Expect(err).To(BeNil())
@@ -866,17 +904,34 @@ ENTRYPOINT /bin/sleep`
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
- // Now make sure that the container's command is set to the
- // entrypoint and it's arguments to "10s".
+ // Now make sure that the container's command in the kube yaml is NOT set to the
+ // entrypoint but the arguments should be set to "10s".
pod := new(v1.Pod)
err = yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
containers := pod.Spec.Containers
Expect(len(containers)).To(Equal(1))
-
- Expect(containers[0].Command).To(Equal([]string{"/bin/sh", "-c", "/bin/sleep"}))
Expect(containers[0].Args).To(Equal([]string{"10s"}))
+
+ session = podmanTest.Podman([]string{"create", "--pod", "new:testpod-2", "--entrypoint", "echo", image, "hello"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ kube = podmanTest.Podman([]string{"generate", "kube", "testpod-2"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ // Now make sure that the container's command in the kube yaml is set to the
+ // entrypoint defined by the --entrypoint flag and the arguments should be set to "hello".
+ pod = new(v1.Pod)
+ err = yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ containers = pod.Spec.Containers
+ Expect(len(containers)).To(Equal(1))
+ Expect(containers[0].Command).To(Equal([]string{"echo"}))
+ Expect(containers[0].Args).To(Equal([]string{"hello"}))
})
It("podman generate kube - --privileged container", func() {
@@ -942,7 +997,7 @@ USER test1`
pod := new(v1.Pod)
err = yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
- Expect(*pod.Spec.Containers[0].SecurityContext.RunAsUser).To(Equal(int64(10001)))
+ Expect(pod.Spec.Containers[0].SecurityContext.RunAsUser).To(BeNil())
})
It("podman generate kube on named volume", func() {
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 0d5b9d52c..c31b89650 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -18,6 +18,7 @@ import (
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ "github.com/onsi/gomega/format"
. "github.com/onsi/gomega/gexec"
"github.com/opencontainers/selinux/go-selinux"
)
@@ -2722,4 +2723,44 @@ invalid kube kind
exists.WaitWithDefaultTimeout()
Expect(exists).To(Exit(0))
})
+
+ Describe("verify environment variables", func() {
+ var maxLength int
+ BeforeEach(func() {
+ maxLength = format.MaxLength
+ format.MaxLength = 0
+ })
+ AfterEach(func() {
+ format.MaxLength = maxLength
+ })
+
+ It("values containing equal sign", func() {
+ javaToolOptions := `-XX:+IgnoreUnrecognizedVMOptions -XX:+IdleTuningGcOnIdle -Xshareclasses:name=openj9_system_scc,cacheDir=/opt/java/.scc,readonly,nonFatal`
+ openj9JavaOptions := `-XX:+IgnoreUnrecognizedVMOptions -XX:+IdleTuningGcOnIdle -Xshareclasses:name=openj9_system_scc,cacheDir=/opt/java/.scc,readonly,nonFatal -Dosgi.checkConfiguration=false`
+
+ containerfile := fmt.Sprintf(`FROM %s
+ENV JAVA_TOOL_OPTIONS=%q
+ENV OPENJ9_JAVA_OPTIONS=%q
+`,
+ ALPINE, javaToolOptions, openj9JavaOptions)
+
+ image := "podman-kube-test:env"
+ podmanTest.BuildImage(containerfile, image, "false")
+ ctnr := getCtr(withImage(image))
+ pod := getPod(withCtr(ctnr))
+ Expect(generateKubeYaml("pod", pod, kubeYaml)).Should(Succeed())
+
+ play := podmanTest.Podman([]string{"play", "kube", "--start", kubeYaml})
+ play.WaitWithDefaultTimeout()
+ Expect(play).Should(Exit(0))
+
+ inspect := podmanTest.Podman([]string{"container", "inspect", "--format=json", getCtrNameInPod(pod)})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).Should(Exit(0))
+
+ contents := string(inspect.Out.Contents())
+ Expect(contents).To(ContainSubstring(javaToolOptions))
+ Expect(contents).To(ContainSubstring(openj9JavaOptions))
+ })
+ })
})
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 3d9d834b3..8640d427a 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -723,4 +723,10 @@ EOF
is "$output" "Error: strconv.ParseInt: parsing \"a\": invalid syntax"
}
+@test "podman run closes stdin" {
+ random_1=$(random_string 25)
+ run_podman run -i --rm $IMAGE cat <<<"$random_1"
+ is "$output" "$random_1" "output matches STDIN"
+}
+
# vim: filetype=sh
diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats
index 0dae569a8..395e6f94f 100644
--- a/test/system/260-sdnotify.bats
+++ b/test/system/260-sdnotify.bats
@@ -70,7 +70,7 @@ function _stop_socat() {
# Check that MAINPID=xxxxx points to a running conmon process
function _assert_mainpid_is_conmon() {
- local mainpid=$(expr "$1" : "MAINPID=\([0-9]\+\)")
+ local mainpid=$(expr "$1" : ".*MAINPID=\([0-9]\+\)")
test -n "$mainpid" || die "Could not parse '$1' as 'MAINPID=nnnn'"
test -d /proc/$mainpid || die "sdnotify MAINPID=$mainpid - but /proc/$mainpid does not exist"
@@ -121,7 +121,7 @@ function _assert_mainpid_is_conmon() {
# we look for READY=1 _anywhere_ in the output, not just the last line.
is "$output" ".*READY=1.*" "sdnotify sent READY=1"
- _assert_mainpid_is_conmon "${lines[0]}"
+ _assert_mainpid_is_conmon "$output"
# Done. Stop container, clean up.
run_podman exec $cid touch /stop
@@ -163,7 +163,7 @@ function _assert_mainpid_is_conmon() {
is "$output" ".*READY=1" "received READY=1 through notify socket"
- _assert_mainpid_is_conmon "${lines[0]}"
+ _assert_mainpid_is_conmon "$output"
# Done. Stop container, clean up.
run_podman exec $cid touch /stop
diff --git a/test/system/270-socket-activation.bats b/test/system/270-socket-activation.bats
index dd439d3ae..0bdfbdad4 100644
--- a/test/system/270-socket-activation.bats
+++ b/test/system/270-socket-activation.bats
@@ -8,14 +8,16 @@ load helpers.systemd
SERVICE_NAME="podman_test_$(random_string)"
-SERVICE_SOCK_ADDR="/run/podman/podman.sock"
+SERVICE_SOCK_ADDR="/run/podman/$SERVICE_NAME.sock"
if is_rootless; then
- SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/podman.sock"
+ SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/$SERVICE_NAME.sock"
fi
SERVICE_FILE="$UNIT_DIR/$SERVICE_NAME.service"
SOCKET_FILE="$UNIT_DIR/$SERVICE_NAME.socket"
+# URL to use for ping
+_PING=http://placeholder-hostname/libpod/_ping
function setup() {
skip_if_remote "systemd tests are meaningless over remote"
@@ -25,8 +27,8 @@ function setup() {
cat > $SERVICE_FILE <<EOF
[Unit]
Description=Podman API Service
-Requires=podman.socket
-After=podman.socket
+Requires=$SERVICE_NAME.socket
+After=$SERVICE_NAME.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
@@ -42,7 +44,7 @@ Description=Podman API Socket
Documentation=man:podman-system-service(1)
[Socket]
-ListenStream=%t/podman/podman.sock
+ListenStream=%t/podman/$SERVICE_NAME.sock
SocketMode=0660
[Install]
@@ -51,10 +53,10 @@ EOF
# ensure pause die before each test runs
if is_rootless; then
- local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
- if [ -f $pause_pid ]; then
- kill -9 $(cat $pause_pid) 2> /dev/null
- rm -f $pause_pid
+ local pause_pid_file="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
+ if [ -f $pause_pid_file ]; then
+ kill -9 $(< $pause_pid_file) 2> /dev/null
+ rm -f $pause_pid_file
fi
fi
systemctl start "$SERVICE_NAME.socket"
@@ -68,7 +70,9 @@ function teardown() {
}
@test "podman system service - socket activation - no container" {
- run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
+ run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR $_PING
+ echo "curl output: $output"
+ is "$status" "0" "curl exit status"
is "$output" "OK" "podman service responds normally"
}
@@ -76,28 +80,35 @@ function teardown() {
run_podman run -d $IMAGE sleep 90
cid="$output"
- run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
+ run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR $_PING
+ echo "curl output: $output"
+ is "$status" "0" "curl exit status"
is "$output" "OK" "podman service responds normally"
- run_podman stop -t 0 $cid
run_podman rm -f $cid
}
@test "podman system service - socket activation - kill rootless pause" {
if ! is_rootless; then
- skip "root podman no need pause process"
+ skip "there is no pause process when running rootful"
fi
run_podman run -d $IMAGE sleep 90
cid="$output"
- local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
- if [ -f $pause_pid ]; then
- kill -9 $(cat $pause_pid) 2> /dev/null
+ local pause_pid_file="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
+ if [ ! -f $pause_pid_file ]; then
+ # This seems unlikely, but not impossible
+ die "Pause pid file does not exist: $pause_pid_file"
fi
- run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
+
+ echo "kill -9 $(< pause_pid_file)"
+ kill -9 $(< $pause_pid_file)
+
+ run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR $_PING
+ echo "curl output: $output"
+ is "$status" "0" "curl exit status"
is "$output" "OK" "podman service responds normally"
- run_podman stop -t 0 $cid
run_podman rm -f $cid
}
diff --git a/version/version.go b/version/version.go
index 8500c64b8..e5d1f3d1c 100644
--- a/version/version.go
+++ b/version/version.go
@@ -27,7 +27,7 @@ const (
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-var Version = semver.MustParse("3.4.1-dev")
+var Version = semver.MustParse("3.4.2-dev")
// See https://docs.docker.com/engine/api/v1.40/
// libpod compat handlers are expected to honor docker API versions