summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/source/markdown/podman-generate-systemd.1.md2
-rw-r--r--libpod/container_copy_linux.go25
-rw-r--r--libpod/container_inspect.go23
-rw-r--r--pkg/api/handlers/types.go2
-rw-r--r--pkg/api/handlers/utils/containers.go15
-rw-r--r--test/apiv2/26-containersWait.at4
-rw-r--r--test/apiv2/python/rest_api/test_v2_0_0_container.py2
-rw-r--r--test/e2e/cp_test.go44
-rw-r--r--test/system/065-cp.bats16
9 files changed, 115 insertions, 18 deletions
diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md
index 4b77c5721..3565a42bc 100644
--- a/docs/source/markdown/podman-generate-systemd.1.md
+++ b/docs/source/markdown/podman-generate-systemd.1.md
@@ -10,7 +10,7 @@ podman\-generate\-systemd - Generate systemd unit file(s) for a container or pod
**podman generate systemd** will create a systemd unit file that can be used to control a container or pod.
By default, the command will print the content of the unit files to stdout.
-_Note: If you use this command with the remote client, you would still have to place the generated units on the remote system._
+_Note: If you use this command with the remote client, you would still have to place the generated units on the remote system. Moreover, please make sure that the XDG_RUNTIME_DIR environment variable is set. If unset, you may set it via `export XDG_RUNTIME_DIR=/run/user/$(id -u)`._
## OPTIONS
diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go
index 5c275c641..0ab322829 100644
--- a/libpod/container_copy_linux.go
+++ b/libpod/container_copy_linux.go
@@ -237,21 +237,32 @@ func (c *Container) joinMountAndExec(ctx context.Context, f func() error) error
}
defer mountFD.Close()
- pidFD, err := getFD(PIDNS)
+ inHostPidNS, err := c.inHostPidNS()
if err != nil {
- errChan <- err
+ errChan <- errors.Wrap(err, "checking inHostPidNS")
return
}
- defer pidFD.Close()
- if err := unix.Unshare(unix.CLONE_NEWNS); err != nil {
- errChan <- err
- return
+ var pidFD *os.File
+ if !inHostPidNS {
+ pidFD, err = getFD(PIDNS)
+ if err != nil {
+ errChan <- err
+ return
+ }
+ defer pidFD.Close()
}
- if err := unix.Setns(int(pidFD.Fd()), unix.CLONE_NEWPID); err != nil {
+
+ if err := unix.Unshare(unix.CLONE_NEWNS); err != nil {
errChan <- err
return
}
+ if pidFD != nil {
+ if err := unix.Setns(int(pidFD.Fd()), unix.CLONE_NEWPID); err != nil {
+ errChan <- err
+ return
+ }
+ }
if err := unix.Setns(int(mountFD.Fd()), unix.CLONE_NEWNS); err != nil {
errChan <- err
return
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 4210bc581..638e0b756 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -892,3 +892,26 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
return hostConfig, nil
}
+
+// Return true if the container is running in the host's PID NS.
+func (c *Container) inHostPidNS() (bool, error) {
+ if c.config.PIDNsCtr != "" {
+ return false, nil
+ }
+ ctrSpec, err := c.specFromState()
+ if err != nil {
+ return false, err
+ }
+ if ctrSpec.Linux != nil {
+ // Locate the spec's PID namespace.
+ // If there is none, it's pid=host.
+ // If there is one and it has a path, it's "ns:".
+ // If there is no path, it's default - the empty string.
+ for _, ns := range ctrSpec.Linux.Namespaces {
+ if ns.Type == spec.PIDNamespace {
+ return false, nil
+ }
+ }
+ }
+ return true, nil
+}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 52d7633af..2ffd9b0cb 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -98,7 +98,7 @@ type BuildResult struct {
type ContainerWaitOKBody struct {
StatusCode int
- Error struct {
+ Error *struct {
Message string
}
}
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 6c708f74e..fb1f8b7c1 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -75,18 +75,19 @@ func WaitContainerDocker(w http.ResponseWriter, r *http.Request) {
}
exitCode, err := waitDockerCondition(ctx, name, interval, condition)
- msg := ""
+ var errStruct *struct{ Message string }
if err != nil {
logrus.Errorf("error while waiting on condition: %q", err)
- msg = err.Error()
+ errStruct = &struct {
+ Message string
+ }{
+ Message: err.Error(),
+ }
}
+
responseData := handlers.ContainerWaitOKBody{
StatusCode: int(exitCode),
- Error: struct {
- Message string
- }{
- Message: msg,
- },
+ Error: errStruct,
}
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
diff --git a/test/apiv2/26-containersWait.at b/test/apiv2/26-containersWait.at
index ec16c35df..55bcd4592 100644
--- a/test/apiv2/26-containersWait.at
+++ b/test/apiv2/26-containersWait.at
@@ -21,7 +21,9 @@ t POST "containers/${CTR}/wait?condition=non-existent-cond" 400
t POST "containers/${CTR}/wait?condition=not-running" 200
-t POST "containers/${CTR}/wait?condition=next-exit" 200 &
+t POST "containers/${CTR}/wait?condition=next-exit" 200 \
+ .StatusCode=0 \
+ .Error=null &
child_pid=$!
podman start "${CTR}"
wait "${child_pid}"
diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index 70c07d47f..ad096ed38 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -99,7 +99,7 @@ class ContainerTestCase(APITestCase):
r = requests.post(self.podman_url + f"/v1.40/containers/{create['Id']}/wait")
self.assertEqual(r.status_code, 200, r.text)
wait = r.json()
- self.assertEqual(wait["StatusCode"], 0, wait["Error"]["Message"])
+ self.assertEqual(wait["StatusCode"], 0, wait["Error"])
prune = requests.post(self.podman_url + "/v1.40/containers/prune")
self.assertEqual(prune.status_code, 200, prune.status_code)
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index c0fb3f887..be4901833 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -91,6 +91,50 @@ var _ = Describe("Podman cp", func() {
Expect(roundtripContent).To(Equal(originalContent))
})
+ // Copy a file to the container, then back to the host in --pid=host
+ It("podman cp --pid=host file", func() {
+ SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
+ srcFile, err := ioutil.TempFile("", "")
+ Expect(err).To(BeNil())
+ defer srcFile.Close()
+ defer os.Remove(srcFile.Name())
+
+ originalContent := []byte("podman cp file test")
+ err = ioutil.WriteFile(srcFile.Name(), originalContent, 0644)
+ Expect(err).To(BeNil())
+
+ // Create a container. NOTE that container mustn't be running for copying.
+ session := podmanTest.Podman([]string{"create", "--pid=host", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ name := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"start", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // The file will now be created (and written to).
+ session = podmanTest.Podman([]string{"cp", srcFile.Name(), name + ":foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // Copy FROM the container.
+
+ destFile, err := ioutil.TempFile("", "")
+ Expect(err).To(BeNil())
+ defer destFile.Close()
+ defer os.Remove(destFile.Name())
+
+ session = podmanTest.Podman([]string{"cp", name + ":foo", destFile.Name()})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // Now make sure the content matches.
+ roundtripContent, err := ioutil.ReadFile(destFile.Name())
+ Expect(err).To(BeNil())
+ Expect(roundtripContent).To(Equal(originalContent))
+ })
+
// Create a symlink in the container, use it as a copy destination and
// make sure that the link and the resolved path are accessible and
// give the right content.
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index 679cdc209..24ac8118e 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -130,6 +130,22 @@ load helpers
}
+@test "podman cp file from/to host while --pid=host" {
+ if is_rootless && ! is_cgroupsv2; then
+ skip "'podman cp --pid=host' (rootless) only works with cgroups v2"
+ fi
+
+ srcdir=$PODMAN_TMPDIR/cp-pid-equals-host
+ mkdir -p $srcdir
+ touch $srcdir/hostfile
+
+ run_podman run --pid=host -d --name cpcontainer $IMAGE sleep infinity
+ run_podman cp $srcdir/hostfile cpcontainer:/tmp/hostfile
+ run_podman cp cpcontainer:/tmp/hostfile $srcdir/hostfile1
+ run_podman kill cpcontainer
+ run_podman rm -f cpcontainer
+}
+
@test "podman cp file from container to host" {
srcdir=$PODMAN_TMPDIR/cp-test-file-ctr-to-host
mkdir -p $srcdir