diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container.go | 25 | ||||
-rw-r--r-- | libpod/container_api.go | 4 | ||||
-rw-r--r-- | libpod/container_internal.go | 14 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 4 | ||||
-rw-r--r-- | libpod/healthcheck.go | 2 | ||||
-rw-r--r-- | libpod/oci.go | 1 | ||||
-rw-r--r-- | libpod/oci_linux.go | 53 | ||||
-rw-r--r-- | libpod/options.go | 9 | ||||
-rw-r--r-- | libpod/runtime.go | 14 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 7 |
10 files changed, 115 insertions, 18 deletions
diff --git a/libpod/container.go b/libpod/container.go index 6d5e063ab..de4674222 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 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_internal.go b/libpod/container_internal.go index 22df36c11..36b5e01df 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -350,7 +350,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 { @@ -948,7 +948,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 @@ -1064,14 +1064,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 } @@ -1111,13 +1113,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 @@ -1125,7 +1127,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..eeffa4705 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 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/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..85b860268 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 } |