summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go27
-rw-r--r--libpod/container_api.go4
-rw-r--r--libpod/container_commit.go17
-rw-r--r--libpod/container_internal.go16
-rw-r--r--libpod/container_internal_linux.go35
-rw-r--r--libpod/healthcheck.go2
-rw-r--r--libpod/kube.go2
-rw-r--r--libpod/oci.go1
-rw-r--r--libpod/oci_linux.go53
-rw-r--r--libpod/options.go9
-rw-r--r--libpod/runtime.go14
-rw-r--r--libpod/runtime_ctr.go17
12 files changed, 149 insertions, 48 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 6d5e063ab..4bf9a1ba9 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -363,7 +363,7 @@ type ContainerConfig struct {
// Systemd tells libpod to setup the container in systemd mode
Systemd bool `json:"systemd"`
- // HealtchCheckConfig has the health check command and related timings
+ // HealthCheckConfig has the health check command and related timings
HealthCheckConfig *manifest.Schema2HealthConfig `json:"healthcheck"`
}
@@ -401,6 +401,29 @@ func (t ContainerStatus) String() string {
return "bad state"
}
+// StringToContainerStatus converts a string representation of a containers
+// status into an actual container status type
+func StringToContainerStatus(status string) (ContainerStatus, error) {
+ switch status {
+ case ContainerStateUnknown.String():
+ return ContainerStateUnknown, nil
+ case ContainerStateConfigured.String():
+ return ContainerStateConfigured, nil
+ case ContainerStateCreated.String():
+ return ContainerStateCreated, nil
+ case ContainerStateRunning.String():
+ return ContainerStateRunning, nil
+ case ContainerStateStopped.String():
+ return ContainerStateStopped, nil
+ case ContainerStatePaused.String():
+ return ContainerStatePaused, nil
+ case ContainerStateExited.String():
+ return ContainerStateExited, nil
+ default:
+ return ContainerStateUnknown, errors.Wrapf(ErrInvalidArg, "unknown container state: %s", status)
+ }
+}
+
// Config accessors
// Unlocked
@@ -591,7 +614,7 @@ func (c *Container) NewNetNS() bool {
func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
// First check if the container belongs to a network namespace (like a pod)
if len(c.config.NetNsCtr) > 0 {
- netNsCtr, err := c.runtime.LookupContainer(c.config.NetNsCtr)
+ netNsCtr, err := c.runtime.GetContainer(c.config.NetNsCtr)
if err != nil {
return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
}
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 2a2381923..465b23831 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -15,7 +15,7 @@ import (
"github.com/containers/libpod/pkg/lookup"
"github.com/containers/storage/pkg/stringid"
"github.com/docker/docker/oci/caps"
- opentracing "github.com/opentracing/opentracing-go"
+ "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/wait"
@@ -174,7 +174,7 @@ func (c *Container) StopWithTimeout(timeout uint) error {
if c.state.State == ContainerStateConfigured ||
c.state.State == ContainerStateUnknown ||
c.state.State == ContainerStatePaused {
- return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers")
+ return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers. %s in state %s", c.ID(), c.state.State.String())
}
if c.state.State == ContainerStateStopped ||
diff --git a/libpod/container_commit.go b/libpod/container_commit.go
index 0604a550b..db67f7a30 100644
--- a/libpod/container_commit.go
+++ b/libpod/container_commit.go
@@ -20,10 +20,11 @@ import (
//libpod
type ContainerCommitOptions struct {
buildah.CommitOptions
- Pause bool
- Author string
- Message string
- Changes []string
+ Pause bool
+ IncludeVolumes bool
+ Author string
+ Message string
+ Changes []string
}
// ChangeCmds is the list of valid Changes commands to passed to the Commit call
@@ -113,9 +114,11 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
// User
importBuilder.SetUser(c.User())
// Volumes
- for _, v := range c.config.UserVolumes {
- if v != "" {
- importBuilder.AddVolume(v)
+ if options.IncludeVolumes {
+ for _, v := range c.config.UserVolumes {
+ if v != "" {
+ importBuilder.AddVolume(v)
+ }
}
}
// Workdir
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 485b43f7d..927b71b2b 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -340,7 +340,7 @@ func (c *Container) teardownStorage() error {
artifacts := filepath.Join(c.config.StaticDir, artifactsDir)
if err := os.RemoveAll(artifacts); err != nil {
- return errors.Wrapf(err, "error removing artifacts %q", artifacts)
+ return errors.Wrapf(err, "error removing container %s artifacts %q", c.ID(), artifacts)
}
if err := c.cleanupStorage(); err != nil {
@@ -666,7 +666,7 @@ func (c *Container) getAllDependencies(visited map[string]*Container) error {
}
for _, depID := range depIDs {
if _, ok := visited[depID]; !ok {
- dep, err := c.runtime.state.LookupContainer(depID)
+ dep, err := c.runtime.state.Container(depID)
if err != nil {
return err
}
@@ -938,7 +938,7 @@ func (c *Container) start() error {
// Internal, non-locking function to stop container
func (c *Container) stop(timeout uint) error {
- logrus.Debugf("Stopping ctr %s with timeout %d", c.ID(), timeout)
+ logrus.Debugf("Stopping ctr %s (timeout %d)", c.ID(), timeout)
if err := c.runtime.ociRuntime.stopContainer(c, timeout); err != nil {
return err
@@ -1054,14 +1054,16 @@ func (c *Container) mountStorage() (string, error) {
func (c *Container) cleanupStorage() error {
if !c.state.Mounted {
// Already unmounted, do nothing
- logrus.Debugf("Storage is already unmounted, skipping...")
+ logrus.Debugf("Container %s storage is already unmounted, skipping...", c.ID())
return nil
}
+
for _, mount := range c.config.Mounts {
if err := c.unmountSHM(mount); err != nil {
return err
}
}
+
if c.config.Rootfs != "" {
return nil
}
@@ -1101,13 +1103,13 @@ func (c *Container) cleanup(ctx context.Context) error {
// Remove healthcheck unit/timer file if it execs
if c.config.HealthCheckConfig != nil {
if err := c.removeTimer(); err != nil {
- logrus.Error(err)
+ logrus.Errorf("Error removing timer for container %s healthcheck: %v", c.ID(), err)
}
}
// Clean up network namespace, if present
if err := c.cleanupNetwork(); err != nil {
- lastError = err
+ lastError = errors.Wrapf(err, "error removing container %s network", c.ID())
}
// Unmount storage
@@ -1115,7 +1117,7 @@ func (c *Container) cleanup(ctx context.Context) error {
if lastError != nil {
logrus.Errorf("Error unmounting container %s storage: %v", c.ID(), err)
} else {
- lastError = err
+ lastError = errors.Wrapf(err, "error unmounting container %s storage", c.ID())
}
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 4d6bf61a3..f352b188e 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -30,7 +30,7 @@ import (
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
- opentracing "github.com/opentracing/opentracing-go"
+ "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@@ -48,6 +48,8 @@ func (c *Container) unmountSHM(mount string) error {
if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil {
if err != syscall.EINVAL {
logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err)
+ } else {
+ logrus.Debugf("container %s failed to unmount %s : %v", c.ID(), mount, err)
}
}
return nil
@@ -502,17 +504,9 @@ func (c *Container) checkpointRestoreSupported() (err error) {
return nil
}
-func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
- if err := c.checkpointRestoreSupported(); err != nil {
- return err
- }
-
- if c.state.State != ContainerStateRunning {
- return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State)
- }
-
+func (c *Container) checkpointRestoreLabelLog(fileName string) (err error) {
// Create the CRIU log file and label it
- dumpLog := filepath.Join(c.bundlePath(), "dump.log")
+ dumpLog := filepath.Join(c.bundlePath(), fileName)
logFile, err := os.OpenFile(dumpLog, os.O_CREATE, 0600)
if err != nil {
@@ -522,6 +516,21 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
if err = label.SetFileLabel(dumpLog, c.MountLabel()); err != nil {
return errors.Wrapf(err, "failed to label CRIU log file %q", dumpLog)
}
+ return nil
+}
+
+func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) (err error) {
+ if err := c.checkpointRestoreSupported(); err != nil {
+ return err
+ }
+
+ if c.state.State != ContainerStateRunning {
+ return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State)
+ }
+
+ if err := c.checkpointRestoreLabelLog("dump.log"); err != nil {
+ return err
+ }
if err := c.runtime.ociRuntime.checkpointContainer(c, options); err != nil {
return err
@@ -575,6 +584,10 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
return errors.Wrapf(err, "A complete checkpoint for this container cannot be found, cannot restore")
}
+ if err := c.checkpointRestoreLabelLog("restore.log"); err != nil {
+ return err
+ }
+
// Read network configuration from checkpoint
// Currently only one interface with one IP is supported.
networkStatusFile, err := os.Open(filepath.Join(c.bundlePath(), "network.status"))
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index d8f56860b..3a6609740 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -41,7 +41,7 @@ const (
HealthCheckDefined HealthCheckStatus = iota
// MaxHealthCheckNumberLogs is the maximum number of attempts we keep
- // in the healtcheck history file
+ // in the healthcheck history file
MaxHealthCheckNumberLogs int = 5
// MaxHealthCheckLogLength in characters
MaxHealthCheckLogLength = 500
diff --git a/libpod/kube.go b/libpod/kube.go
index 484127870..260269b2e 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -69,7 +69,7 @@ func (p *Pod) getInfraContainer() (*Container, error) {
if err != nil {
return nil, err
}
- return p.runtime.LookupContainer(infraID)
+ return p.runtime.GetContainer(infraID)
}
// GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object
diff --git a/libpod/oci.go b/libpod/oci.go
index 62331b879..189359753 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -143,6 +143,7 @@ func waitContainerStop(ctr *Container, timeout time.Duration) error {
return nil
case <-time.After(timeout):
close(chControl)
+ logrus.Debugf("container %s did not die within timeout %d", ctr.ID(), timeout)
return errors.Errorf("container %s did not die within timeout", ctr.ID())
}
}
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 8c0abad80..01f7c3649 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -3,15 +3,20 @@
package libpod
import (
+ "fmt"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"syscall"
"github.com/containerd/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/utils"
+ pmount "github.com/containers/storage/pkg/mount"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -91,6 +96,54 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor
return err
}
}
+
+ // if we are running a non privileged container, be sure to umount some kernel paths so they are not
+ // bind mounted inside the container at all.
+ if !ctr.config.Privileged && !rootless.IsRootless() {
+ ch := make(chan error)
+ go func() {
+ runtime.LockOSThread()
+ err := func() error {
+ fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+
+ // create a new mountns on the current thread
+ if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
+ return err
+ }
+ defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS)
+
+ // don't spread our mounts around. We are setting only /sys to be slave
+ // so that the cleanup process is still able to umount the storage and the
+ // changes are propagated to the host.
+ err = unix.Mount("/sys", "/sys", "none", unix.MS_REC|unix.MS_SLAVE, "")
+ if err != nil {
+ return errors.Wrapf(err, "cannot make /sys slave")
+ }
+
+ mounts, err := pmount.GetMounts()
+ if err != nil {
+ return err
+ }
+ for _, m := range mounts {
+ if !strings.HasPrefix(m.Mountpoint, "/sys/kernel") {
+ continue
+ }
+ err = unix.Unmount(m.Mountpoint, 0)
+ if err != nil {
+ return errors.Wrapf(err, "cannot unmount %s", m.Mountpoint)
+ }
+ }
+ return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
+ }()
+ ch <- err
+ }()
+ err := <-ch
+ return err
+ }
}
return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
}
diff --git a/libpod/options.go b/libpod/options.go
index 9326e54e4..8038f1935 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -17,7 +17,8 @@ import (
)
var (
- nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
+ nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
+ regexError = errors.Wrapf(ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*")
)
// Runtime Creation Options
@@ -593,7 +594,7 @@ func WithName(name string) CtrCreateOption {
// Check the name against a regex
if !nameRegex.MatchString(name) {
- return errors.Wrapf(ErrInvalidArg, "name must match regex [a-zA-Z0-9_-]+")
+ return regexError
}
ctr.config.Name = name
@@ -1276,7 +1277,7 @@ func WithVolumeName(name string) VolumeCreateOption {
// Check the name against a regex
if !nameRegex.MatchString(name) {
- return errors.Wrapf(ErrInvalidArg, "name must match regex [a-zA-Z0-9_-]+")
+ return regexError
}
volume.config.Name = name
@@ -1382,7 +1383,7 @@ func WithPodName(name string) PodCreateOption {
// Check the name against a regex
if !nameRegex.MatchString(name) {
- return errors.Wrapf(ErrInvalidArg, "name must match regex [a-zA-Z0-9_-]+")
+ return regexError
}
pod.config.Name = name
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 4dd2707e8..3b1c2be98 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -870,6 +870,20 @@ func makeRuntime(runtime *Runtime) (err error) {
_, err = os.Stat(runtimeAliveFile)
if err != nil {
+ // If we need to refresh, then it is safe to assume there are
+ // no containers running. Create immediately a namespace, as
+ // we will need to access the storage.
+ if os.Geteuid() != 0 {
+ aliveLock.Unlock()
+ became, ret, err := rootless.BecomeRootInUserNS()
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+
+ }
// If the file doesn't exist, we need to refresh the state
// This will trigger on first use as well, but refreshing an
// empty state only creates a single file
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 800b42851..48c254c0f 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -372,7 +372,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// Clean up network namespace, cgroups, mounts
if err := c.cleanup(ctx); err != nil {
if cleanupErr == nil {
- cleanupErr = err
+ cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID())
} else {
logrus.Errorf("cleanup network, cgroups, mounts: %v", err)
}
@@ -404,12 +404,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// Deallocate the container's lock
if err := c.lock.Free(); err != nil {
if cleanupErr == nil {
- cleanupErr = err
+ cleanupErr = errors.Wrapf(err, "error freeing lock for container %s", c.ID())
} else {
logrus.Errorf("free container lock: %v", err)
}
}
+ c.newContainerEvent(events.Remove)
+
if !removeVolume {
return cleanupErr
}
@@ -425,7 +427,6 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- c.newContainerEvent(events.Remove)
return cleanupErr
}
@@ -547,16 +548,6 @@ func (r *Runtime) GetLatestContainer() (*Container, error) {
return ctrs[lastCreatedIndex], nil
}
-// Export is the libpod portion of exporting a container to a tar file
-func (r *Runtime) Export(name string, path string) error {
- ctr, err := r.LookupContainer(name)
- if err != nil {
- return err
- }
- return ctr.Export(path)
-
-}
-
// RemoveContainersFromStorage attempt to remove containers from storage that do not exist in libpod database
func (r *Runtime) RemoveContainersFromStorage(ctrs []string) {
for _, i := range ctrs {