aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/checkpoint_restore.go29
-rw-r--r--pkg/adapter/containers.go4
-rw-r--r--pkg/adapter/pods.go5
-rw-r--r--pkg/adapter/runtime.go3
-rw-r--r--pkg/adapter/terminal_linux.go6
-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/netns/netns_linux.go17
-rw-r--r--pkg/rootless/rootless_linux.go24
-rw-r--r--pkg/spec/spec.go56
-rw-r--r--pkg/spec/spec_linux.go42
-rw-r--r--pkg/spec/spec_unsupported.go7
-rw-r--r--pkg/spec/storage.go7
17 files changed, 210 insertions, 44 deletions
diff --git a/pkg/adapter/checkpoint_restore.go b/pkg/adapter/checkpoint_restore.go
index 97ba5ecf7..ec1464fb1 100644
--- a/pkg/adapter/checkpoint_restore.go
+++ b/pkg/adapter/checkpoint_restore.go
@@ -4,16 +4,19 @@ package adapter
import (
"context"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/storage/pkg/archive"
jsoniter "github.com/json-iterator/go"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
+ "github.com/sirupsen/logrus"
)
// Prefixing the checkpoint/restore related functions with 'cr'
@@ -25,7 +28,7 @@ func crImportFromJSON(filePath string, v interface{}) error {
if err != nil {
return errors.Wrapf(err, "Failed to open container definition %s for restore", filePath)
}
- defer jsonFile.Close()
+ defer errorhandling.CloseQuiet(jsonFile)
content, err := ioutil.ReadAll(jsonFile)
if err != nil {
@@ -48,7 +51,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
if err != nil {
return nil, errors.Wrapf(err, "Failed to open checkpoint archive %s for import", input)
}
- defer archiveFile.Close()
+ defer errorhandling.CloseQuiet(archiveFile)
options := &archive.TarOptions{
// Here we only need the files config.dump and spec.dump
ExcludePatterns: []string{
@@ -62,15 +65,19 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
if err != nil {
return nil, err
}
- defer os.RemoveAll(dir)
+ defer func() {
+ if err := os.RemoveAll(dir); err != nil {
+ logrus.Errorf("could not recursively remove %s: %q", dir, err)
+ }
+ }()
err = archive.Untar(archiveFile, dir, options)
if err != nil {
return nil, errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input)
}
// Load spec.dump from temporary directory
- spec := new(spec.Spec)
- if err := crImportFromJSON(filepath.Join(dir, "spec.dump"), spec); err != nil {
+ dumpSpec := new(spec.Spec)
+ if err := crImportFromJSON(filepath.Join(dir, "spec.dump"), dumpSpec); err != nil {
return nil, err
}
@@ -112,7 +119,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
}
// Now create a new container from the just loaded information
- container, err := runtime.RestoreContainer(ctx, spec, config)
+ container, err := runtime.RestoreContainer(ctx, dumpSpec, config)
if err != nil {
return nil, err
}
@@ -127,7 +134,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
return nil, errors.Errorf("Name of restored container (%s) does not match requested name (%s)", containerConfig.Name, ctrName)
}
- if newName == false {
+ if !newName {
// Only check ID for a restore with the same name.
// Using -n to request a new name for the restored container, will also create a new ID
if containerConfig.ID != ctrID {
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 1cf9d686a..86e9c0266 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -213,8 +213,8 @@ func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmVa
c := c
pool.Add(shared.Job{
- c.ID(),
- func() error {
+ ID: c.ID(),
+ Fn: func() error {
err := r.RemoveContainer(ctx, c, cli.Force, cli.Volumes)
if err != nil {
logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index a28e1ab4b..b45b02d09 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -70,8 +70,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal
for _, p := range pods {
p := p
- pool.Add(shared.Job{p.ID(),
- func() error {
+ pool.Add(shared.Job{
+ ID: p.ID(),
+ Fn: func() error {
err := r.Runtime.RemovePod(ctx, p, cli.Force, cli.Force)
if err != nil {
logrus.Debugf("Failed to remove pod %s: %s", p.ID(), err.Error())
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 8ef88f36b..e65f07898 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -359,9 +359,6 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
if eventsError != nil {
return eventsError
}
- if err != nil {
- return errors.Wrapf(err, "unable to tail the events log")
- }
w := bufio.NewWriter(os.Stdout)
for event := range eventChannel {
if len(c.Format) > 0 {
diff --git a/pkg/adapter/terminal_linux.go b/pkg/adapter/terminal_linux.go
index be7dc0cb6..e3255ecb6 100644
--- a/pkg/adapter/terminal_linux.go
+++ b/pkg/adapter/terminal_linux.go
@@ -39,7 +39,11 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr,
return err
}
- defer restoreTerminal(oldTermState)
+ defer func() {
+ if err := restoreTerminal(oldTermState); err != nil {
+ logrus.Errorf("unable to restore terminal: %q", err)
+ }
+ }()
}
streams := new(libpod.AttachStreams)
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 fc9847a51..fda19bff8 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -332,6 +332,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 {
@@ -359,11 +366,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 {
@@ -372,8 +408,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/netns/netns_linux.go b/pkg/netns/netns_linux.go
index 4a515c72a..1d6fb873c 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -28,6 +28,7 @@ import (
"sync"
"github.com/containernetworking/plugins/pkg/ns"
+ "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -90,7 +91,9 @@ func NewNS() (ns.NetNS, error) {
// Ensure the mount point is cleaned up on errors; if the namespace
// was successfully mounted this will have no effect because the file
// is in-use
- defer os.RemoveAll(nsPath)
+ defer func() {
+ _ = os.RemoveAll(nsPath)
+ }()
var wg sync.WaitGroup
wg.Add(1)
@@ -109,7 +112,11 @@ func NewNS() (ns.NetNS, error) {
if err != nil {
return
}
- defer origNS.Close()
+ defer func() {
+ if err := origNS.Close(); err != nil {
+ logrus.Errorf("unable to close namespace: %q", err)
+ }
+ }()
// create a new netns on the current thread
err = unix.Unshare(unix.CLONE_NEWNET)
@@ -118,7 +125,11 @@ func NewNS() (ns.NetNS, error) {
}
// Put this thread back to the orig ns, since it might get reused (pre go1.10)
- defer origNS.Set()
+ defer func() {
+ if err := origNS.Set(); err != nil {
+ logrus.Errorf("unable to set namespace: %q", err)
+ }
+ }()
// bind mount the netns from the current thread (from /proc) onto the
// mount point. This causes the namespace to persist, even when there
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index d7c2de81d..99a0eb729 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -220,7 +220,11 @@ func EnableLinger() (string, error) {
conn, err := dbus.SystemBus()
if err == nil {
- defer conn.Close()
+ defer func() {
+ if err := conn.Close(); err != nil {
+ logrus.Errorf("unable to close dbus connection: %q", err)
+ }
+ }()
}
lingerEnabled := false
@@ -310,13 +314,21 @@ func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
if err != nil {
return false, -1, err
}
- defer userNS.Close()
+ defer func() {
+ if err := userNS.Close(); err != nil {
+ logrus.Errorf("unable to close namespace: %q", err)
+ }
+ }()
mountNS, err := os.Open(fmt.Sprintf("/proc/%d/ns/mnt", pid))
if err != nil {
return false, -1, err
}
- defer userNS.Close()
+ defer func() {
+ if err := mountNS.Close(); err != nil {
+ logrus.Errorf("unable to close namespace: %q", err)
+ }
+ }()
fd, err := getUserNSFirstChild(userNS.Fd())
if err != nil {
@@ -364,7 +376,11 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
defer errorhandling.CloseQuiet(r)
defer errorhandling.CloseQuiet(w)
- defer w.Write([]byte("0"))
+ defer func() {
+ if _, err := w.Write([]byte("0")); err != nil {
+ logrus.Errorf("failed to write byte 0: %q", err)
+ }
+ }()
pidC := C.reexec_in_user_namespace(C.int(r.Fd()), cPausePid, cFileToRead, fileOutputFD)
pid := int(pidC)
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 5cc021bf5..53b73296a 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 {
@@ -80,23 +86,41 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
g.AddLinuxMaskedPaths("/sys/kernel")
}
}
+ gid5Available := true
if isRootless {
nGids, err := getAvailableGids()
if err != nil {
return nil, err
}
- if nGids < 5 {
- // If we have no GID mappings, the gid=5 default option would fail, so drop it.
- g.RemoveMount("/dev/pts")
- devPts := spec.Mount{
- Destination: "/dev/pts",
- Type: "devpts",
- Source: "devpts",
- Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+ gid5Available = nGids >= 5
+ }
+ // When using a different user namespace, check that the GID 5 is mapped inside
+ // the container.
+ if gid5Available && len(config.IDMappings.GIDMap) > 0 {
+ mappingFound := false
+ for _, r := range config.IDMappings.GIDMap {
+ if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
+ mappingFound = true
+ break
}
- g.AddMount(devPts)
}
+ if !mappingFound {
+ gid5Available = false
+ }
+
+ }
+ if !gid5Available {
+ // If we have no GID mappings, the gid=5 default option would fail, so drop it.
+ g.RemoveMount("/dev/pts")
+ devPts := spec.Mount{
+ Destination: "/dev/pts",
+ Type: "devpts",
+ Source: "devpts",
+ Options: []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+ }
+ g.AddMount(devPts)
}
+
if inUserNS && config.IpcMode.IsHost() {
g.RemoveMount("/dev/mqueue")
devMqueue := spec.Mount{
@@ -557,6 +581,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/pkg/spec/storage.go b/pkg/spec/storage.go
index ed767f5ba..88f1f6dc1 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -211,6 +211,13 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount,
}
mount.Options = opts
}
+ if mount.Type == TypeBind {
+ absSrc, err := filepath.Abs(mount.Source)
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
+ }
+ mount.Source = absSrc
+ }
finalMounts = append(finalMounts, mount)
}
finalVolumes := make([]*libpod.ContainerNamedVolume, 0, len(baseVolumes))