summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml14
-rw-r--r--docs/podman-create.1.md2
-rw-r--r--docs/podman-run.1.md2
-rw-r--r--libpod/container_internal_linux.go1
-rw-r--r--pkg/cgroups/blkio.go2
-rw-r--r--pkg/cgroups/cgroups.go41
-rw-r--r--pkg/cgroups/cpu.go2
-rw-r--r--pkg/cgroups/cpuset.go3
-rw-r--r--pkg/cgroups/memory.go3
-rw-r--r--pkg/cgroups/pids.go3
-rw-r--r--pkg/spec/spec.go20
-rw-r--r--pkg/spec/spec_linux.go42
-rw-r--r--pkg/spec/spec_unsupported.go7
-rw-r--r--test/README.md23
-rw-r--r--test/e2e/pod_rm_test.go17
-rw-r--r--test/e2e/run_test.go21
16 files changed, 181 insertions, 22 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index dac41dc5f..da28bb597 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -215,7 +215,8 @@ build_each_commit_task:
on_failure:
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
-build_without_cgo:
+
+build_without_cgo_task:
depends_on:
- "gating"
@@ -475,17 +476,18 @@ verify_test_built_images_task:
always:
<<: *standardlogs
-
-# Post message to IRC if everything passed
+# Post message to IRC if everything passed PR testing
success_task:
only_if: $CIRRUS_BRANCH != 'master'
- depends_on: # ignores any dependent task conditions
+ # ignores any dependent task conditions, include everything except 'release'
+ depends_on: &alltasks
- "gating"
- "vendor"
- "varlink_api"
- "build_each_commit"
+ - "build_without_cgo"
- "meta"
- "testing"
- "special_testing_rootless"
@@ -493,7 +495,6 @@ success_task:
- "special_testing_cross"
- "test_build_cache_images"
- "verify_test_built_images"
- - "build_without_cgo"
env:
CIRRUS_WORKING_DIR: "/usr/src/libpod"
@@ -514,8 +515,7 @@ release_task:
# allow_failures: $CI == "true"
# skip_notifications: $CI == "true"
- depends_on:
- - "success"
+ depends_on: *alltasks
gce_instance:
image_name: "${IMAGE_BUILDER_CACHE_IMAGE_NAME}"
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 9cf3e038d..a34111a03 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -723,6 +723,8 @@ The following example maps uids 0-2000 in the container to the uids 30000-31999
Ulimit options
+You can pass `host` to copy the current configuration from the host.
+
**--user**, **-u**=*user*
Sets the username or UID used and optionally the groupname or GID for the specified command.
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index 4889e5755..86cc2125c 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -759,6 +759,8 @@ The example maps uids 0-2000 in the container to the uids 30000-31999 on the hos
Ulimit options
+You can pass `host` to copy the current configuration from the host.
+
**--user**, **-u**=*user*
Sets the username or UID used and optionally the groupname or GID for the specified command.
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 686a595de..aa477611f 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -636,6 +636,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
}
}
+ c.state.FinishedTime = time.Now()
return c.save()
}
diff --git a/pkg/cgroups/blkio.go b/pkg/cgroups/blkio.go
index 9c2a811d9..bacd4eb93 100644
--- a/pkg/cgroups/blkio.go
+++ b/pkg/cgroups/blkio.go
@@ -37,7 +37,7 @@ func (c *blkioHandler) Create(ctr *CgroupControl) (bool, error) {
// Destroy the cgroup
func (c *blkioHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Blkio))
+ return rmDirRecursively(ctr.getCgroupv1Path(Blkio))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 1dad45d7f..081db772f 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -328,6 +328,13 @@ func Load(path string) (*CgroupControl, error) {
systemd: false,
}
if !cgroup2 {
+ controllers, err := getAvailableControllers(handlers, false)
+ if err != nil {
+ return nil, err
+ }
+ control.additionalControllers = controllers
+ }
+ if !cgroup2 {
for name := range handlers {
p := control.getCgroupv1Path(name)
if _, err := os.Stat(p); err != nil {
@@ -355,11 +362,40 @@ func (c *CgroupControl) Delete() error {
return c.DeleteByPath(c.path)
}
+// rmDirRecursively delete recursively a cgroup directory.
+// It differs from os.RemoveAll as it doesn't attempt to unlink files.
+// On cgroupfs we are allowed only to rmdir empty directories.
+func rmDirRecursively(path string) error {
+ if err := os.Remove(path); err == nil || os.IsNotExist(err) {
+ return nil
+ }
+ entries, err := ioutil.ReadDir(path)
+ if err != nil {
+ return errors.Wrapf(err, "read %s", path)
+ }
+ for _, i := range entries {
+ if i.IsDir() {
+ if err := rmDirRecursively(filepath.Join(path, i.Name())); err != nil {
+ return err
+ }
+ }
+ }
+ if os.Remove(path); err != nil {
+ if !os.IsNotExist(err) {
+ return errors.Wrapf(err, "remove %s", path)
+ }
+ }
+ return nil
+}
+
// DeleteByPath deletes the specified cgroup path
func (c *CgroupControl) DeleteByPath(path string) error {
if c.systemd {
return systemdDestroy(path)
}
+ if c.cgroup2 {
+ return rmDirRecursively(filepath.Join(cgroupRoot, c.path))
+ }
var lastError error
for _, h := range handlers {
if err := h.Destroy(c); err != nil {
@@ -368,8 +404,11 @@ func (c *CgroupControl) DeleteByPath(path string) error {
}
for _, ctr := range c.additionalControllers {
+ if ctr.symlink {
+ continue
+ }
p := c.getCgroupv1Path(ctr.name)
- if err := os.Remove(p); err != nil {
+ if err := rmDirRecursively(p); err != nil {
lastError = errors.Wrapf(err, "remove %s", p)
}
}
diff --git a/pkg/cgroups/cpu.go b/pkg/cgroups/cpu.go
index 1c8610cc4..03677f1ef 100644
--- a/pkg/cgroups/cpu.go
+++ b/pkg/cgroups/cpu.go
@@ -68,7 +68,7 @@ func (c *cpuHandler) Create(ctr *CgroupControl) (bool, error) {
// Destroy the cgroup
func (c *cpuHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(CPU))
+ return rmDirRecursively(ctr.getCgroupv1Path(CPU))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/cpuset.go b/pkg/cgroups/cpuset.go
index 25d2f7f76..46d0484f2 100644
--- a/pkg/cgroups/cpuset.go
+++ b/pkg/cgroups/cpuset.go
@@ -3,7 +3,6 @@ package cgroups
import (
"fmt"
"io/ioutil"
- "os"
"path/filepath"
"strings"
@@ -77,7 +76,7 @@ func (c *cpusetHandler) Create(ctr *CgroupControl) (bool, error) {
// Destroy the cgroup
func (c *cpusetHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(CPUset))
+ return rmDirRecursively(ctr.getCgroupv1Path(CPUset))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/memory.go b/pkg/cgroups/memory.go
index 80e88d17c..b3991f7e3 100644
--- a/pkg/cgroups/memory.go
+++ b/pkg/cgroups/memory.go
@@ -2,7 +2,6 @@ package cgroups
import (
"fmt"
- "os"
"path/filepath"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -33,7 +32,7 @@ func (c *memHandler) Create(ctr *CgroupControl) (bool, error) {
// Destroy the cgroup
func (c *memHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Memory))
+ return rmDirRecursively(ctr.getCgroupv1Path(Memory))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/cgroups/pids.go b/pkg/cgroups/pids.go
index ffbde100d..65b9b5b34 100644
--- a/pkg/cgroups/pids.go
+++ b/pkg/cgroups/pids.go
@@ -3,7 +3,6 @@ package cgroups
import (
"fmt"
"io/ioutil"
- "os"
"path/filepath"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -40,7 +39,7 @@ func (c *pidHandler) Create(ctr *CgroupControl) (bool, error) {
// Destroy the cgroup
func (c *pidHandler) Destroy(ctr *CgroupControl) error {
- return os.Remove(ctr.getCgroupv1Path(Pids))
+ return rmDirRecursively(ctr.getCgroupv1Path(Pids))
}
// Stat fills a metrics structure with usage stats for the controller
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 5cc021bf5..d44beb3e4 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -20,6 +20,12 @@ import (
const cpuPeriod = 100000
+type systemUlimit struct {
+ name string
+ max uint64
+ cur uint64
+}
+
func getAvailableGids() (int64, error) {
idMap, err := user.ParseIDMapFile("/proc/self/gid_map")
if err != nil {
@@ -557,6 +563,20 @@ func addRlimits(config *CreateConfig, g *generate.Generator) error {
)
for _, u := range config.Resources.Ulimit {
+ if u == "host" {
+ if len(config.Resources.Ulimit) != 1 {
+ return errors.New("ulimit can use host only once")
+ }
+ hostLimits, err := getHostRlimits()
+ if err != nil {
+ return err
+ }
+ for _, i := range hostLimits {
+ g.AddProcessRlimits(i.name, i.max, i.cur)
+ }
+ break
+ }
+
ul, err := units.ParseUlimit(u)
if err != nil {
return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
diff --git a/pkg/spec/spec_linux.go b/pkg/spec/spec_linux.go
new file mode 100644
index 000000000..fcdfc5c4e
--- /dev/null
+++ b/pkg/spec/spec_linux.go
@@ -0,0 +1,42 @@
+//+build linux
+
+package createconfig
+
+import (
+ "syscall"
+
+ "github.com/pkg/errors"
+)
+
+type systemRlimit struct {
+ name string
+ value int
+}
+
+var systemLimits = []systemRlimit{
+ {"RLIMIT_AS", syscall.RLIMIT_AS},
+ {"RLIMIT_CORE", syscall.RLIMIT_CORE},
+ {"RLIMIT_CPU", syscall.RLIMIT_CPU},
+ {"RLIMIT_DATA", syscall.RLIMIT_DATA},
+ {"RLIMIT_FSIZE", syscall.RLIMIT_FSIZE},
+ {"RLIMIT_NOFILE", syscall.RLIMIT_NOFILE},
+ {"RLIMIT_STACK", syscall.RLIMIT_STACK},
+}
+
+func getHostRlimits() ([]systemUlimit, error) {
+ ret := []systemUlimit{}
+ for _, i := range systemLimits {
+ var l syscall.Rlimit
+ if err := syscall.Getrlimit(i.value, &l); err != nil {
+ return nil, errors.Wrapf(err, "cannot read limits for %s", i.name)
+ }
+ s := systemUlimit{
+ name: i.name,
+ max: l.Max,
+ cur: l.Cur,
+ }
+ ret = append(ret, s)
+ }
+ return ret, nil
+
+}
diff --git a/pkg/spec/spec_unsupported.go b/pkg/spec/spec_unsupported.go
new file mode 100644
index 000000000..0f6a9acdc
--- /dev/null
+++ b/pkg/spec/spec_unsupported.go
@@ -0,0 +1,7 @@
+//+build !linux
+
+package createconfig
+
+func getHostRlimits() ([]systemUlimit, error) {
+ return nil, nil
+}
diff --git a/test/README.md b/test/README.md
index 4e61a0774..9bea679dc 100644
--- a/test/README.md
+++ b/test/README.md
@@ -110,19 +110,30 @@ make shell
This will run a container and give you a shell and you can follow the instructions above.
-# System test
+# System tests
System tests are used for testing the *podman* CLI in the context of a complete system. It
requires that *podman*, all dependencies, and configurations are in place. The intention of
system testing is to match as closely as possible with real-world user/developer use-cases
and environments. The orchestration of the environments and tests is left to external
tooling.
-* `PodmanTestSystem`: System test *struct* as a composite of `PodmanTest`. It will not add any
-options to the command by default. When you run system test, you can set GLOBALOPTIONS,
-PODMAN_SUBCMD_OPTIONS or PODMAN_BINARY in ENV to run the test suite for different test matrices.
+System tests use Bash Automated Testing System (`bats`) as a testing framework.
+Install it via your package manager or get latest stable version
+[directly from the repository](https://github.com/bats-core/bats-core), e.g.:
-## Run system test
-You can run the test with following command:
+```
+mkdir -p ~/tools/bats
+git clone --single-branch --branch v1.1.0 https://github.com/bats-core/bats-core.git ~/tools/bats
+```
+
+Make sure that `bats` binary (`bin/bats` in the repository) is in your `PATH`, if not - add it:
+
+```
+PATH=$PATH:~/tools/bats/bin
+```
+
+## Running system tests
+When `bats` is installed and is in your `PATH`, you can run the test suite with following command:
```
make localsystem
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 0d3f47f30..f0689f152 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -3,6 +3,8 @@ package integration
import (
"fmt"
"os"
+ "path/filepath"
+ "strings"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
@@ -40,6 +42,21 @@ var _ = Describe("Podman pod rm", func() {
result := podmanTest.Podman([]string{"pod", "rm", podid})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
+
+ // Also check that we don't leak cgroups
+ err := filepath.Walk("/sys/fs/cgroup", func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if !info.IsDir() {
+ Expect(err).To(BeNil())
+ }
+ if strings.Contains(info.Name(), podid) {
+ return fmt.Errorf("leaking cgroup path %s", path)
+ }
+ return nil
+ })
+ Expect(err).To(BeNil())
})
It("podman pod rm latest pod", func() {
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 3fc628589..f95c5298d 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -8,7 +8,9 @@ import (
"net"
"os"
"path/filepath"
+ "strconv"
"strings"
+ "syscall"
"time"
. "github.com/containers/libpod/test/utils"
@@ -250,6 +252,25 @@ var _ = Describe("Podman run", func() {
Expect(session.OutputToString()).To(ContainSubstring("100"))
})
+ It("podman run limits host test", func() {
+ SkipIfRemote()
+
+ var l syscall.Rlimit
+
+ err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
+ Expect(err).To(BeNil())
+
+ session := podmanTest.Podman([]string{"run", "--rm", "--ulimit", "host", fedoraMinimal, "ulimit", "-Hn"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ ulimitCtrStr := strings.TrimSpace(session.OutputToString())
+ ulimitCtr, err := strconv.ParseUint(ulimitCtrStr, 10, 0)
+ Expect(err).To(BeNil())
+
+ Expect(ulimitCtr).Should(BeNumerically(">=", l.Max))
+ })
+
It("podman run with cidfile", func() {
session := podmanTest.Podman([]string{"run", "--cidfile", tempdir + "cidfile", ALPINE, "ls"})
session.WaitWithDefaultTimeout()